Bug 1690340 - Part 1: Hide all the panel tools in the developer tools menu. r=jdescottes
[gecko.git] / parser / html / nsHtml5TreeBuilder.cpp
blob8d89c61afe35dff2e16b2b350686dc0f0e08c275
1 /*
2 * Copyright (c) 2007 Henri Sivonen
3 * Copyright (c) 2007-2017 Mozilla Foundation
4 * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla
5 * Foundation, and Opera Software ASA.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
27 * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
28 * Please edit TreeBuilder.java instead and regenerate.
31 #define nsHtml5TreeBuilder_cpp__
33 #include "nsContentUtils.h"
34 #include "nsAtom.h"
35 #include "nsHtml5AtomTable.h"
36 #include "nsHtml5String.h"
37 #include "nsNameSpaceManager.h"
38 #include "nsIContent.h"
39 #include "nsTraceRefcnt.h"
40 #include "jArray.h"
41 #include "nsHtml5DocumentMode.h"
42 #include "nsHtml5ArrayCopy.h"
43 #include "nsHtml5Parser.h"
44 #include "nsGkAtoms.h"
45 #include "nsHtml5TreeOperation.h"
46 #include "nsHtml5StateSnapshot.h"
47 #include "nsHtml5StackNode.h"
48 #include "nsHtml5TreeOpExecutor.h"
49 #include "nsHtml5StreamParser.h"
50 #include "nsAHtml5TreeBuilderState.h"
51 #include "nsHtml5Highlighter.h"
52 #include "nsHtml5PlainTextUtils.h"
53 #include "nsHtml5ViewSourceUtils.h"
54 #include "mozilla/ImportScanner.h"
55 #include "mozilla/Likely.h"
56 #include "nsIContentHandle.h"
57 #include "nsHtml5OplessBuilder.h"
59 #include "nsHtml5AttributeName.h"
60 #include "nsHtml5ElementName.h"
61 #include "nsHtml5Tokenizer.h"
62 #include "nsHtml5MetaScanner.h"
63 #include "nsHtml5StackNode.h"
64 #include "nsHtml5UTF16Buffer.h"
65 #include "nsHtml5StateSnapshot.h"
66 #include "nsHtml5Portability.h"
68 #include "nsHtml5TreeBuilder.h"
70 char16_t nsHtml5TreeBuilder::REPLACEMENT_CHARACTER[] = {0xfffd};
71 static const char* const QUIRKY_PUBLIC_IDS_DATA[] = {
72 "+//silmaril//dtd html pro v0r11 19970101//",
73 "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
74 "-//as//dtd html 3.0 aswedit + extensions//",
75 "-//ietf//dtd html 2.0 level 1//",
76 "-//ietf//dtd html 2.0 level 2//",
77 "-//ietf//dtd html 2.0 strict level 1//",
78 "-//ietf//dtd html 2.0 strict level 2//",
79 "-//ietf//dtd html 2.0 strict//",
80 "-//ietf//dtd html 2.0//",
81 "-//ietf//dtd html 2.1e//",
82 "-//ietf//dtd html 3.0//",
83 "-//ietf//dtd html 3.2 final//",
84 "-//ietf//dtd html 3.2//",
85 "-//ietf//dtd html 3//",
86 "-//ietf//dtd html level 0//",
87 "-//ietf//dtd html level 1//",
88 "-//ietf//dtd html level 2//",
89 "-//ietf//dtd html level 3//",
90 "-//ietf//dtd html strict level 0//",
91 "-//ietf//dtd html strict level 1//",
92 "-//ietf//dtd html strict level 2//",
93 "-//ietf//dtd html strict level 3//",
94 "-//ietf//dtd html strict//",
95 "-//ietf//dtd html//",
96 "-//metrius//dtd metrius presentational//",
97 "-//microsoft//dtd internet explorer 2.0 html strict//",
98 "-//microsoft//dtd internet explorer 2.0 html//",
99 "-//microsoft//dtd internet explorer 2.0 tables//",
100 "-//microsoft//dtd internet explorer 3.0 html strict//",
101 "-//microsoft//dtd internet explorer 3.0 html//",
102 "-//microsoft//dtd internet explorer 3.0 tables//",
103 "-//netscape comm. corp.//dtd html//",
104 "-//netscape comm. corp.//dtd strict html//",
105 "-//o'reilly and associates//dtd html 2.0//",
106 "-//o'reilly and associates//dtd html extended 1.0//",
107 "-//o'reilly and associates//dtd html extended relaxed 1.0//",
108 "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html "
109 "4.0//",
110 "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
111 "-//spyglass//dtd html 2.0 extended//",
112 "-//sq//dtd html 2.0 hotmetal + extensions//",
113 "-//sun microsystems corp.//dtd hotjava html//",
114 "-//sun microsystems corp.//dtd hotjava strict html//",
115 "-//w3c//dtd html 3 1995-03-24//",
116 "-//w3c//dtd html 3.2 draft//",
117 "-//w3c//dtd html 3.2 final//",
118 "-//w3c//dtd html 3.2//",
119 "-//w3c//dtd html 3.2s draft//",
120 "-//w3c//dtd html 4.0 frameset//",
121 "-//w3c//dtd html 4.0 transitional//",
122 "-//w3c//dtd html experimental 19960712//",
123 "-//w3c//dtd html experimental 970421//",
124 "-//w3c//dtd w3 html//",
125 "-//w3o//dtd w3 html 3.0//",
126 "-//webtechs//dtd mozilla html 2.0//",
127 "-//webtechs//dtd mozilla html//"};
128 staticJArray<const char*, int32_t> nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS = {
129 QUIRKY_PUBLIC_IDS_DATA, MOZ_ARRAY_LENGTH(QUIRKY_PUBLIC_IDS_DATA)};
130 void nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self) {
131 tokenizer = self;
132 stackNodes = jArray<nsHtml5StackNode*, int32_t>::newJArray(64);
133 stack = jArray<nsHtml5StackNode*, int32_t>::newJArray(64);
134 templateModeStack = jArray<int32_t, int32_t>::newJArray(64);
135 listOfActiveFormattingElements =
136 jArray<nsHtml5StackNode*, int32_t>::newJArray(64);
137 needToDropLF = false;
138 originalMode = INITIAL;
139 templateModePtr = -1;
140 stackNodesIdx = 0;
141 numStackNodes = 0;
142 currentPtr = -1;
143 listPtr = -1;
144 formPointer = nullptr;
145 headPointer = nullptr;
146 start(fragment);
147 charBufferLen = 0;
148 charBuffer = nullptr;
149 framesetOk = true;
150 if (fragment) {
151 nsIContentHandle* elt;
152 if (contextNode) {
153 elt = contextNode;
154 } else {
155 elt = createHtmlElementSetAsRoot(tokenizer->emptyAttributes());
157 if (contextNamespace == kNameSpaceID_SVG) {
158 nsHtml5ElementName* elementName = nsHtml5ElementName::ELT_SVG;
159 if (nsGkAtoms::title == contextName || nsGkAtoms::desc == contextName ||
160 nsGkAtoms::foreignObject == contextName) {
161 elementName = nsHtml5ElementName::ELT_FOREIGNOBJECT;
163 nsHtml5StackNode* node =
164 createStackNode(elementName, elementName->getCamelCaseName(), elt);
165 currentPtr++;
166 stack[currentPtr] = node;
167 tokenizer->setState(nsHtml5Tokenizer::DATA);
168 mode = FRAMESET_OK;
169 } else if (contextNamespace == kNameSpaceID_MathML) {
170 nsHtml5ElementName* elementName = nsHtml5ElementName::ELT_MATH;
171 if (nsGkAtoms::mi_ == contextName || nsGkAtoms::mo_ == contextName ||
172 nsGkAtoms::mn_ == contextName || nsGkAtoms::ms_ == contextName ||
173 nsGkAtoms::mtext_ == contextName) {
174 elementName = nsHtml5ElementName::ELT_MTEXT;
175 } else if (nsGkAtoms::annotation_xml_ == contextName) {
176 elementName = nsHtml5ElementName::ELT_ANNOTATION_XML;
178 nsHtml5StackNode* node =
179 createStackNode(elementName, elt, elementName->getName(), false);
180 currentPtr++;
181 stack[currentPtr] = node;
182 tokenizer->setState(nsHtml5Tokenizer::DATA);
183 mode = FRAMESET_OK;
184 } else {
185 nsHtml5StackNode* node =
186 createStackNode(nsHtml5ElementName::ELT_HTML, elt);
187 currentPtr++;
188 stack[currentPtr] = node;
189 if (nsGkAtoms::_template == contextName) {
190 pushTemplateMode(IN_TEMPLATE);
192 resetTheInsertionMode();
193 formPointer = getFormPointerForContext(contextNode);
194 if (nsGkAtoms::title == contextName ||
195 nsGkAtoms::textarea == contextName) {
196 tokenizer->setState(nsHtml5Tokenizer::RCDATA);
197 } else if (nsGkAtoms::style == contextName ||
198 nsGkAtoms::xmp == contextName ||
199 nsGkAtoms::iframe == contextName ||
200 nsGkAtoms::noembed == contextName ||
201 nsGkAtoms::noframes == contextName ||
202 (scriptingEnabled && nsGkAtoms::noscript == contextName)) {
203 tokenizer->setState(nsHtml5Tokenizer::RAWTEXT);
204 } else if (nsGkAtoms::plaintext == contextName) {
205 tokenizer->setState(nsHtml5Tokenizer::PLAINTEXT);
206 } else if (nsGkAtoms::script == contextName) {
207 tokenizer->setState(nsHtml5Tokenizer::SCRIPT_DATA);
208 } else {
209 tokenizer->setState(nsHtml5Tokenizer::DATA);
212 } else {
213 mode = INITIAL;
214 if (tokenizer->isViewingXmlSource()) {
215 nsIContentHandle* elt = createElement(
216 kNameSpaceID_SVG, nsGkAtoms::svg, tokenizer->emptyAttributes(),
217 nullptr, svgCreator(NS_NewSVGSVGElement));
218 nsHtml5StackNode* node =
219 createStackNode(nsHtml5ElementName::ELT_SVG, nsGkAtoms::svg, elt);
220 currentPtr++;
221 stack[currentPtr] = node;
226 void nsHtml5TreeBuilder::doctype(nsAtom* name, nsHtml5String publicIdentifier,
227 nsHtml5String systemIdentifier,
228 bool forceQuirks) {
229 needToDropLF = false;
230 if (!isInForeign() && mode == INITIAL) {
231 nsHtml5String emptyString = nsHtml5Portability::newEmptyString();
232 appendDoctypeToDocument(!name ? nsGkAtoms::_empty : name,
233 !publicIdentifier ? emptyString : publicIdentifier,
234 !systemIdentifier ? emptyString : systemIdentifier);
235 emptyString.Release();
236 if (isQuirky(name, publicIdentifier, systemIdentifier, forceQuirks)) {
237 errQuirkyDoctype();
238 documentModeInternal(QUIRKS_MODE, publicIdentifier, systemIdentifier);
239 } else if (isAlmostStandards(publicIdentifier, systemIdentifier)) {
240 errAlmostStandardsDoctype();
241 documentModeInternal(ALMOST_STANDARDS_MODE, publicIdentifier,
242 systemIdentifier);
243 } else {
244 documentModeInternal(STANDARDS_MODE, publicIdentifier, systemIdentifier);
246 mode = BEFORE_HTML;
247 return;
249 errStrayDoctype();
250 return;
253 void nsHtml5TreeBuilder::comment(char16_t* buf, int32_t start, int32_t length) {
254 needToDropLF = false;
255 if (!isInForeign()) {
256 switch (mode) {
257 case INITIAL:
258 case BEFORE_HTML:
259 case AFTER_AFTER_BODY:
260 case AFTER_AFTER_FRAMESET: {
261 appendCommentToDocument(buf, start, length);
262 return;
264 case AFTER_BODY: {
265 flushCharacters();
266 appendComment(stack[0]->node, buf, start, length);
267 return;
269 default: {
270 break;
274 flushCharacters();
275 appendComment(stack[currentPtr]->node, buf, start, length);
276 return;
279 void nsHtml5TreeBuilder::characters(const char16_t* buf, int32_t start,
280 int32_t length) {
281 if (tokenizer->isViewingXmlSource()) {
282 return;
284 if (needToDropLF) {
285 needToDropLF = false;
286 if (buf[start] == '\n') {
287 start++;
288 length--;
289 if (!length) {
290 return;
294 switch (mode) {
295 case IN_BODY:
296 case IN_CELL:
297 case IN_CAPTION: {
298 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
299 reconstructTheActiveFormattingElements();
301 [[fallthrough]];
303 case TEXT: {
304 accumulateCharacters(buf, start, length);
305 return;
307 case IN_TABLE:
308 case IN_TABLE_BODY:
309 case IN_ROW: {
310 accumulateCharactersForced(buf, start, length);
311 return;
313 default: {
314 int32_t end = start + length;
315 for (int32_t i = start; i < end; i++) {
316 switch (buf[i]) {
317 case ' ':
318 case '\t':
319 case '\n':
320 case '\r':
321 case '\f': {
322 switch (mode) {
323 case INITIAL:
324 case BEFORE_HTML:
325 case BEFORE_HEAD: {
326 start = i + 1;
327 continue;
329 case IN_HEAD:
330 case IN_HEAD_NOSCRIPT:
331 case AFTER_HEAD:
332 case IN_COLUMN_GROUP:
333 case IN_FRAMESET:
334 case AFTER_FRAMESET: {
335 continue;
337 case FRAMESET_OK:
338 case IN_TEMPLATE:
339 case IN_BODY:
340 case IN_CELL:
341 case IN_CAPTION: {
342 if (start < i) {
343 accumulateCharacters(buf, start, i - start);
344 start = i;
346 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
347 flushCharacters();
348 reconstructTheActiveFormattingElements();
350 NS_HTML5_BREAK(charactersloop);
352 case IN_SELECT:
353 case IN_SELECT_IN_TABLE: {
354 NS_HTML5_BREAK(charactersloop);
356 case IN_TABLE:
357 case IN_TABLE_BODY:
358 case IN_ROW: {
359 accumulateCharactersForced(buf, i, 1);
360 start = i + 1;
361 continue;
363 case AFTER_BODY:
364 case AFTER_AFTER_BODY:
365 case AFTER_AFTER_FRAMESET: {
366 if (start < i) {
367 accumulateCharacters(buf, start, i - start);
368 start = i;
370 flushCharacters();
371 reconstructTheActiveFormattingElements();
372 continue;
375 MOZ_FALLTHROUGH_ASSERT();
377 default: {
378 switch (mode) {
379 case INITIAL: {
380 documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
381 mode = BEFORE_HTML;
382 i--;
383 continue;
385 case BEFORE_HTML: {
386 appendHtmlElementToDocumentAndPush();
387 mode = BEFORE_HEAD;
388 i--;
389 continue;
391 case BEFORE_HEAD: {
392 if (start < i) {
393 accumulateCharacters(buf, start, i - start);
394 start = i;
396 flushCharacters();
397 appendToCurrentNodeAndPushHeadElement(
398 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
399 mode = IN_HEAD;
400 i--;
401 continue;
403 case IN_HEAD: {
404 if (start < i) {
405 accumulateCharacters(buf, start, i - start);
406 start = i;
408 flushCharacters();
409 pop();
410 mode = AFTER_HEAD;
411 i--;
412 continue;
414 case IN_HEAD_NOSCRIPT: {
415 if (start < i) {
416 accumulateCharacters(buf, start, i - start);
417 start = i;
419 errNonSpaceInNoscriptInHead();
420 flushCharacters();
421 pop();
422 mode = IN_HEAD;
423 i--;
424 continue;
426 case AFTER_HEAD: {
427 if (start < i) {
428 accumulateCharacters(buf, start, i - start);
429 start = i;
431 flushCharacters();
432 appendToCurrentNodeAndPushBodyElement();
433 mode = FRAMESET_OK;
434 i--;
435 continue;
437 case FRAMESET_OK: {
438 framesetOk = false;
439 mode = IN_BODY;
440 i--;
441 continue;
443 case IN_TEMPLATE:
444 case IN_BODY:
445 case IN_CELL:
446 case IN_CAPTION: {
447 if (start < i) {
448 accumulateCharacters(buf, start, i - start);
449 start = i;
451 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
452 flushCharacters();
453 reconstructTheActiveFormattingElements();
455 NS_HTML5_BREAK(charactersloop);
457 case IN_TABLE:
458 case IN_TABLE_BODY:
459 case IN_ROW: {
460 accumulateCharactersForced(buf, i, 1);
461 start = i + 1;
462 continue;
464 case IN_COLUMN_GROUP: {
465 if (start < i) {
466 accumulateCharacters(buf, start, i - start);
467 start = i;
469 if (!currentPtr || stack[currentPtr]->getGroup() ==
470 nsHtml5TreeBuilder::TEMPLATE) {
471 errNonSpaceInColgroupInFragment();
472 start = i + 1;
473 continue;
475 flushCharacters();
476 pop();
477 mode = IN_TABLE;
478 i--;
479 continue;
481 case IN_SELECT:
482 case IN_SELECT_IN_TABLE: {
483 NS_HTML5_BREAK(charactersloop);
485 case AFTER_BODY: {
486 errNonSpaceAfterBody();
488 mode = framesetOk ? FRAMESET_OK : IN_BODY;
489 i--;
490 continue;
492 case IN_FRAMESET: {
493 if (start < i) {
494 accumulateCharacters(buf, start, i - start);
496 errNonSpaceInFrameset();
497 start = i + 1;
498 continue;
500 case AFTER_FRAMESET: {
501 if (start < i) {
502 accumulateCharacters(buf, start, i - start);
504 errNonSpaceAfterFrameset();
505 start = i + 1;
506 continue;
508 case AFTER_AFTER_BODY: {
509 errNonSpaceInTrailer();
510 mode = framesetOk ? FRAMESET_OK : IN_BODY;
511 i--;
512 continue;
514 case AFTER_AFTER_FRAMESET: {
515 if (start < i) {
516 accumulateCharacters(buf, start, i - start);
518 errNonSpaceInTrailer();
519 start = i + 1;
520 continue;
526 charactersloop_end:;
527 if (start < end) {
528 accumulateCharacters(buf, start, end - start);
534 void nsHtml5TreeBuilder::zeroOriginatingReplacementCharacter() {
535 if (mode == TEXT) {
536 accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1);
537 return;
539 if (currentPtr >= 0) {
540 if (isSpecialParentInForeign(stack[currentPtr])) {
541 return;
543 accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1);
547 void nsHtml5TreeBuilder::eof() {
548 flushCharacters();
549 for (;;) {
550 switch (mode) {
551 case INITIAL: {
552 documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
553 mode = BEFORE_HTML;
554 continue;
556 case BEFORE_HTML: {
557 appendHtmlElementToDocumentAndPush();
558 mode = BEFORE_HEAD;
559 continue;
561 case BEFORE_HEAD: {
562 appendToCurrentNodeAndPushHeadElement(
563 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
564 mode = IN_HEAD;
565 continue;
567 case IN_HEAD: {
568 while (currentPtr > 0) {
569 popOnEof();
571 mode = AFTER_HEAD;
572 continue;
574 case IN_HEAD_NOSCRIPT: {
575 while (currentPtr > 1) {
576 popOnEof();
578 mode = IN_HEAD;
579 continue;
581 case AFTER_HEAD: {
582 appendToCurrentNodeAndPushBodyElement();
583 mode = IN_BODY;
584 continue;
586 case IN_TABLE_BODY:
587 case IN_ROW:
588 case IN_TABLE:
589 case IN_SELECT_IN_TABLE:
590 case IN_SELECT:
591 case IN_COLUMN_GROUP:
592 case FRAMESET_OK:
593 case IN_CAPTION:
594 case IN_CELL:
595 case IN_BODY: {
596 if (isTemplateModeStackEmpty()) {
597 NS_HTML5_BREAK(eofloop);
599 [[fallthrough]];
601 case IN_TEMPLATE: {
602 int32_t eltPos = findLast(nsGkAtoms::_template);
603 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
604 MOZ_ASSERT(fragment);
605 NS_HTML5_BREAK(eofloop);
607 if (MOZ_UNLIKELY(mViewSource)) {
608 errUnclosedElements(eltPos, nsGkAtoms::_template);
610 while (currentPtr >= eltPos) {
611 pop();
613 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
614 popTemplateMode();
615 resetTheInsertionMode();
616 continue;
618 case TEXT: {
619 if (originalMode == AFTER_HEAD) {
620 popOnEof();
622 popOnEof();
623 mode = originalMode;
624 continue;
626 case IN_FRAMESET: {
627 NS_HTML5_BREAK(eofloop);
629 case AFTER_BODY:
630 case AFTER_FRAMESET:
631 case AFTER_AFTER_BODY:
632 case AFTER_AFTER_FRAMESET:
633 default: {
634 NS_HTML5_BREAK(eofloop);
638 eofloop_end:;
639 while (currentPtr > 0) {
640 popOnEof();
642 if (!fragment) {
643 popOnEof();
647 void nsHtml5TreeBuilder::endTokenization() {
648 formPointer = nullptr;
649 headPointer = nullptr;
650 contextName = nullptr;
651 contextNode = nullptr;
652 templateModeStack = nullptr;
653 if (stack) {
654 while (currentPtr > -1) {
655 stack[currentPtr]->release(this);
656 currentPtr--;
658 stack = nullptr;
660 if (listOfActiveFormattingElements) {
661 while (listPtr > -1) {
662 if (listOfActiveFormattingElements[listPtr]) {
663 listOfActiveFormattingElements[listPtr]->release(this);
665 listPtr--;
667 listOfActiveFormattingElements = nullptr;
669 if (stackNodes) {
670 for (int32_t i = 0; i < numStackNodes; i++) {
671 MOZ_ASSERT(stackNodes[i]->isUnused());
672 delete stackNodes[i];
674 numStackNodes = 0;
675 stackNodesIdx = 0;
676 stackNodes = nullptr;
678 charBuffer = nullptr;
679 end();
682 void nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName,
683 nsHtml5HtmlAttributes* attributes,
684 bool selfClosing) {
685 flushCharacters();
686 int32_t eltPos;
687 needToDropLF = false;
688 starttagloop:
689 for (;;) {
690 int32_t group = elementName->getGroup();
691 nsAtom* name = elementName->getName();
692 if (isInForeign()) {
693 nsHtml5StackNode* currentNode = stack[currentPtr];
694 int32_t currNs = currentNode->ns;
695 if (!(currentNode->isHtmlIntegrationPoint() ||
696 (currNs == kNameSpaceID_MathML &&
697 ((currentNode->getGroup() == MI_MO_MN_MS_MTEXT &&
698 group != MGLYPH_OR_MALIGNMARK) ||
699 (currentNode->getGroup() == ANNOTATION_XML && group == SVG))))) {
700 switch (group) {
701 case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
702 case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
703 case BODY:
704 case BR:
705 case RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR:
706 case DD_OR_DT:
707 case UL_OR_OL_OR_DL:
708 case EMBED:
709 case IMG:
710 case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6:
711 case HEAD:
712 case HR:
713 case LI:
714 case META:
715 case NOBR:
716 case P:
717 case PRE_OR_LISTING:
718 case TABLE:
719 case FONT: {
720 if (!(group == FONT &&
721 !(attributes->contains(nsHtml5AttributeName::ATTR_COLOR) ||
722 attributes->contains(nsHtml5AttributeName::ATTR_FACE) ||
723 attributes->contains(nsHtml5AttributeName::ATTR_SIZE)))) {
724 errHtmlStartTagInForeignContext(name);
725 if (!fragment) {
726 while (!isSpecialParentInForeign(stack[currentPtr])) {
727 popForeign(-1, -1);
729 NS_HTML5_CONTINUE(starttagloop);
732 [[fallthrough]];
734 default: {
735 if (kNameSpaceID_SVG == currNs) {
736 attributes->adjustForSvg();
737 if (selfClosing) {
738 appendVoidElementToCurrentMayFosterSVG(elementName, attributes);
739 selfClosing = false;
740 } else {
741 appendToCurrentNodeAndPushElementMayFosterSVG(elementName,
742 attributes);
744 attributes = nullptr;
745 NS_HTML5_BREAK(starttagloop);
746 } else {
747 attributes->adjustForMath();
748 if (selfClosing) {
749 appendVoidElementToCurrentMayFosterMathML(elementName,
750 attributes);
751 selfClosing = false;
752 } else {
753 appendToCurrentNodeAndPushElementMayFosterMathML(elementName,
754 attributes);
756 attributes = nullptr;
757 NS_HTML5_BREAK(starttagloop);
763 switch (mode) {
764 case IN_TEMPLATE: {
765 switch (group) {
766 case COL: {
767 popTemplateMode();
768 pushTemplateMode(IN_COLUMN_GROUP);
769 mode = IN_COLUMN_GROUP;
770 continue;
772 case CAPTION:
773 case COLGROUP:
774 case TBODY_OR_THEAD_OR_TFOOT: {
775 popTemplateMode();
776 pushTemplateMode(IN_TABLE);
777 mode = IN_TABLE;
778 continue;
780 case TR: {
781 popTemplateMode();
782 pushTemplateMode(IN_TABLE_BODY);
783 mode = IN_TABLE_BODY;
784 continue;
786 case TD_OR_TH: {
787 popTemplateMode();
788 pushTemplateMode(IN_ROW);
789 mode = IN_ROW;
790 continue;
792 case META: {
793 checkMetaCharset(attributes);
794 appendVoidElementToCurrentMayFoster(elementName, attributes);
795 selfClosing = false;
796 attributes = nullptr;
797 NS_HTML5_BREAK(starttagloop);
799 case TITLE: {
800 startTagTitleInHead(elementName, attributes);
801 attributes = nullptr;
802 NS_HTML5_BREAK(starttagloop);
804 case BASE:
805 case LINK_OR_BASEFONT_OR_BGSOUND: {
806 appendVoidElementToCurrentMayFoster(elementName, attributes);
807 selfClosing = false;
808 attributes = nullptr;
809 NS_HTML5_BREAK(starttagloop);
811 case SCRIPT: {
812 startTagScriptInHead(elementName, attributes);
813 attributes = nullptr;
814 NS_HTML5_BREAK(starttagloop);
816 case NOFRAMES:
817 case STYLE: {
818 startTagGenericRawText(elementName, attributes);
819 attributes = nullptr;
820 NS_HTML5_BREAK(starttagloop);
822 case TEMPLATE: {
823 startTagTemplateInHead(elementName, attributes);
824 attributes = nullptr;
825 NS_HTML5_BREAK(starttagloop);
827 default: {
828 popTemplateMode();
829 pushTemplateMode(IN_BODY);
830 mode = IN_BODY;
831 continue;
835 case IN_ROW: {
836 switch (group) {
837 case TD_OR_TH: {
838 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TR));
839 appendToCurrentNodeAndPushElement(elementName, attributes);
840 mode = IN_CELL;
841 insertMarker();
842 attributes = nullptr;
843 NS_HTML5_BREAK(starttagloop);
845 case CAPTION:
846 case COL:
847 case COLGROUP:
848 case TBODY_OR_THEAD_OR_TFOOT:
849 case TR: {
850 eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
851 if (!eltPos) {
852 MOZ_ASSERT(fragment || isTemplateContents());
853 errNoTableRowToClose();
854 NS_HTML5_BREAK(starttagloop);
856 clearStackBackTo(eltPos);
857 pop();
858 mode = IN_TABLE_BODY;
859 continue;
861 default:; // fall through
863 [[fallthrough]];
865 case IN_TABLE_BODY: {
866 switch (group) {
867 case TR: {
868 clearStackBackTo(
869 findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
870 appendToCurrentNodeAndPushElement(elementName, attributes);
871 mode = IN_ROW;
872 attributes = nullptr;
873 NS_HTML5_BREAK(starttagloop);
875 case TD_OR_TH: {
876 errStartTagInTableBody(name);
877 clearStackBackTo(
878 findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
879 appendToCurrentNodeAndPushElement(
880 nsHtml5ElementName::ELT_TR,
881 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
882 mode = IN_ROW;
883 continue;
885 case CAPTION:
886 case COL:
887 case COLGROUP:
888 case TBODY_OR_THEAD_OR_TFOOT: {
889 eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
890 if (!eltPos || stack[eltPos]->getGroup() == TEMPLATE) {
891 MOZ_ASSERT(fragment || isTemplateContents());
892 errStrayStartTag(name);
893 NS_HTML5_BREAK(starttagloop);
894 } else {
895 clearStackBackTo(eltPos);
896 pop();
897 mode = IN_TABLE;
898 continue;
901 default:; // fall through
903 [[fallthrough]];
905 case IN_TABLE: {
906 for (;;) {
907 switch (group) {
908 case CAPTION: {
909 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
910 insertMarker();
911 appendToCurrentNodeAndPushElement(elementName, attributes);
912 mode = IN_CAPTION;
913 attributes = nullptr;
914 NS_HTML5_BREAK(starttagloop);
916 case COLGROUP: {
917 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
918 appendToCurrentNodeAndPushElement(elementName, attributes);
919 mode = IN_COLUMN_GROUP;
920 attributes = nullptr;
921 NS_HTML5_BREAK(starttagloop);
923 case COL: {
924 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
925 appendToCurrentNodeAndPushElement(
926 nsHtml5ElementName::ELT_COLGROUP,
927 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
928 mode = IN_COLUMN_GROUP;
929 NS_HTML5_CONTINUE(starttagloop);
931 case TBODY_OR_THEAD_OR_TFOOT: {
932 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
933 appendToCurrentNodeAndPushElement(elementName, attributes);
934 mode = IN_TABLE_BODY;
935 attributes = nullptr;
936 NS_HTML5_BREAK(starttagloop);
938 case TR:
939 case TD_OR_TH: {
940 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
941 appendToCurrentNodeAndPushElement(
942 nsHtml5ElementName::ELT_TBODY,
943 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
944 mode = IN_TABLE_BODY;
945 NS_HTML5_CONTINUE(starttagloop);
947 case TEMPLATE: {
948 NS_HTML5_BREAK(intableloop);
950 case TABLE: {
951 errTableSeenWhileTableOpen();
952 eltPos = findLastInTableScope(name);
953 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
954 MOZ_ASSERT(fragment || isTemplateContents());
955 NS_HTML5_BREAK(starttagloop);
957 generateImpliedEndTags();
958 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(nsGkAtoms::table)) {
959 errNoCheckUnclosedElementsOnStack();
961 while (currentPtr >= eltPos) {
962 pop();
964 resetTheInsertionMode();
965 NS_HTML5_CONTINUE(starttagloop);
967 case SCRIPT: {
968 appendToCurrentNodeAndPushElement(elementName, attributes);
969 originalMode = mode;
970 mode = TEXT;
971 tokenizer->setStateAndEndTagExpectation(
972 nsHtml5Tokenizer::SCRIPT_DATA, elementName);
973 attributes = nullptr;
974 NS_HTML5_BREAK(starttagloop);
976 case STYLE: {
977 appendToCurrentNodeAndPushElement(elementName, attributes);
978 originalMode = mode;
979 mode = TEXT;
980 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
981 elementName);
982 attributes = nullptr;
983 NS_HTML5_BREAK(starttagloop);
985 case INPUT: {
986 errStartTagInTable(name);
987 if (!nsHtml5Portability::
988 lowerCaseLiteralEqualsIgnoreAsciiCaseString(
989 "hidden", attributes->getValue(
990 nsHtml5AttributeName::ATTR_TYPE))) {
991 NS_HTML5_BREAK(intableloop);
993 appendVoidInputToCurrent(attributes, formPointer);
994 selfClosing = false;
995 attributes = nullptr;
996 NS_HTML5_BREAK(starttagloop);
998 case FORM: {
999 if (!!formPointer || isTemplateContents()) {
1000 errFormWhenFormOpen();
1001 NS_HTML5_BREAK(starttagloop);
1002 } else {
1003 errStartTagInTable(name);
1004 appendVoidFormToCurrent(attributes);
1005 attributes = nullptr;
1006 NS_HTML5_BREAK(starttagloop);
1009 default: {
1010 errStartTagInTable(name);
1011 NS_HTML5_BREAK(intableloop);
1015 intableloop_end:;
1016 [[fallthrough]];
1018 case IN_CAPTION: {
1019 switch (group) {
1020 case CAPTION:
1021 case COL:
1022 case COLGROUP:
1023 case TBODY_OR_THEAD_OR_TFOOT:
1024 case TR:
1025 case TD_OR_TH: {
1026 eltPos = findLastInTableScope(nsGkAtoms::caption);
1027 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1028 MOZ_ASSERT(fragment || isTemplateContents());
1029 errStrayStartTag(name);
1030 NS_HTML5_BREAK(starttagloop);
1032 generateImpliedEndTags();
1033 if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
1034 errNoCheckUnclosedElementsOnStack();
1036 while (currentPtr >= eltPos) {
1037 pop();
1039 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
1040 mode = IN_TABLE;
1041 continue;
1043 default:; // fall through
1045 [[fallthrough]];
1047 case IN_CELL: {
1048 switch (group) {
1049 case CAPTION:
1050 case COL:
1051 case COLGROUP:
1052 case TBODY_OR_THEAD_OR_TFOOT:
1053 case TR:
1054 case TD_OR_TH: {
1055 eltPos = findLastInTableScopeTdTh();
1056 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1057 errNoCellToClose();
1058 NS_HTML5_BREAK(starttagloop);
1059 } else {
1060 closeTheCell(eltPos);
1061 continue;
1064 default:; // fall through
1066 [[fallthrough]];
1068 case FRAMESET_OK: {
1069 switch (group) {
1070 case FRAMESET: {
1071 if (mode == FRAMESET_OK) {
1072 if (!currentPtr || stack[1]->getGroup() != BODY) {
1073 MOZ_ASSERT(fragment || isTemplateContents());
1074 errStrayStartTag(name);
1075 NS_HTML5_BREAK(starttagloop);
1076 } else {
1077 errFramesetStart();
1078 detachFromParent(stack[1]->node);
1079 while (currentPtr > 0) {
1080 pop();
1082 appendToCurrentNodeAndPushElement(elementName, attributes);
1083 mode = IN_FRAMESET;
1084 attributes = nullptr;
1085 NS_HTML5_BREAK(starttagloop);
1087 } else {
1088 errStrayStartTag(name);
1089 NS_HTML5_BREAK(starttagloop);
1092 case PRE_OR_LISTING:
1093 case LI:
1094 case DD_OR_DT:
1095 case BUTTON:
1096 case MARQUEE_OR_APPLET:
1097 case OBJECT:
1098 case TABLE:
1099 case AREA_OR_WBR:
1100 case KEYGEN:
1101 case BR:
1102 case EMBED:
1103 case IMG:
1104 case INPUT:
1105 case HR:
1106 case TEXTAREA:
1107 case XMP:
1108 case IFRAME:
1109 case SELECT: {
1110 if (mode == FRAMESET_OK &&
1111 !(group == INPUT &&
1112 nsHtml5Portability::
1113 lowerCaseLiteralEqualsIgnoreAsciiCaseString(
1114 "hidden", attributes->getValue(
1115 nsHtml5AttributeName::ATTR_TYPE)))) {
1116 framesetOk = false;
1117 mode = IN_BODY;
1119 [[fallthrough]];
1121 default:; // fall through
1123 [[fallthrough]];
1125 case IN_BODY: {
1126 for (;;) {
1127 switch (group) {
1128 case HTML: {
1129 errStrayStartTag(name);
1130 if (!fragment && !isTemplateContents()) {
1131 addAttributesToHtml(attributes);
1132 attributes = nullptr;
1134 NS_HTML5_BREAK(starttagloop);
1136 case BASE:
1137 case LINK_OR_BASEFONT_OR_BGSOUND:
1138 case META:
1139 case STYLE:
1140 case SCRIPT:
1141 case TITLE:
1142 case TEMPLATE: {
1143 NS_HTML5_BREAK(inbodyloop);
1145 case BODY: {
1146 if (!currentPtr || stack[1]->getGroup() != BODY ||
1147 isTemplateContents()) {
1148 MOZ_ASSERT(fragment || isTemplateContents());
1149 errStrayStartTag(name);
1150 NS_HTML5_BREAK(starttagloop);
1152 errFooSeenWhenFooOpen(name);
1153 framesetOk = false;
1154 if (mode == FRAMESET_OK) {
1155 mode = IN_BODY;
1157 if (addAttributesToBody(attributes)) {
1158 attributes = nullptr;
1160 NS_HTML5_BREAK(starttagloop);
1162 case P:
1163 case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
1164 case UL_OR_OL_OR_DL:
1165 case ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY: {
1166 implicitlyCloseP();
1167 appendToCurrentNodeAndPushElementMayFoster(elementName,
1168 attributes);
1169 attributes = nullptr;
1170 NS_HTML5_BREAK(starttagloop);
1172 case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: {
1173 implicitlyCloseP();
1174 if (stack[currentPtr]->getGroup() ==
1175 H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
1176 errHeadingWhenHeadingOpen();
1177 pop();
1179 appendToCurrentNodeAndPushElementMayFoster(elementName,
1180 attributes);
1181 attributes = nullptr;
1182 NS_HTML5_BREAK(starttagloop);
1184 case FIELDSET: {
1185 implicitlyCloseP();
1186 appendToCurrentNodeAndPushElementMayFoster(
1187 elementName, attributes, formPointer);
1188 attributes = nullptr;
1189 NS_HTML5_BREAK(starttagloop);
1191 case PRE_OR_LISTING: {
1192 implicitlyCloseP();
1193 appendToCurrentNodeAndPushElementMayFoster(elementName,
1194 attributes);
1195 needToDropLF = true;
1196 attributes = nullptr;
1197 NS_HTML5_BREAK(starttagloop);
1199 case FORM: {
1200 if (!!formPointer && !isTemplateContents()) {
1201 errFormWhenFormOpen();
1202 NS_HTML5_BREAK(starttagloop);
1203 } else {
1204 implicitlyCloseP();
1205 appendToCurrentNodeAndPushFormElementMayFoster(attributes);
1206 attributes = nullptr;
1207 NS_HTML5_BREAK(starttagloop);
1210 case LI:
1211 case DD_OR_DT: {
1212 eltPos = currentPtr;
1213 for (;;) {
1214 nsHtml5StackNode* node = stack[eltPos];
1215 if (node->getGroup() == group) {
1216 generateImpliedEndTagsExceptFor(node->name);
1217 if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
1218 errUnclosedElementsImplied(eltPos, name);
1220 while (currentPtr >= eltPos) {
1221 pop();
1223 break;
1224 } else if (!eltPos || (node->isSpecial() &&
1225 (node->ns != kNameSpaceID_XHTML ||
1226 (node->name != nsGkAtoms::p &&
1227 node->name != nsGkAtoms::address &&
1228 node->name != nsGkAtoms::div)))) {
1229 break;
1231 eltPos--;
1233 implicitlyCloseP();
1234 appendToCurrentNodeAndPushElementMayFoster(elementName,
1235 attributes);
1236 attributes = nullptr;
1237 NS_HTML5_BREAK(starttagloop);
1239 case PLAINTEXT: {
1240 implicitlyCloseP();
1241 appendToCurrentNodeAndPushElementMayFoster(elementName,
1242 attributes);
1243 tokenizer->setStateAndEndTagExpectation(
1244 nsHtml5Tokenizer::PLAINTEXT, elementName);
1245 attributes = nullptr;
1246 NS_HTML5_BREAK(starttagloop);
1248 case A: {
1249 int32_t activeAPos =
1250 findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(
1251 nsGkAtoms::a);
1252 if (activeAPos != -1) {
1253 errFooSeenWhenFooOpen(name);
1254 nsHtml5StackNode* activeA =
1255 listOfActiveFormattingElements[activeAPos];
1256 activeA->retain();
1257 adoptionAgencyEndTag(nsGkAtoms::a);
1258 removeFromStack(activeA);
1259 activeAPos = findInListOfActiveFormattingElements(activeA);
1260 if (activeAPos != -1) {
1261 removeFromListOfActiveFormattingElements(activeAPos);
1263 activeA->release(this);
1265 reconstructTheActiveFormattingElements();
1266 appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
1267 attributes);
1268 attributes = nullptr;
1269 NS_HTML5_BREAK(starttagloop);
1271 case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
1272 case FONT: {
1273 reconstructTheActiveFormattingElements();
1274 maybeForgetEarlierDuplicateFormattingElement(
1275 elementName->getName(), attributes);
1276 appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
1277 attributes);
1278 attributes = nullptr;
1279 NS_HTML5_BREAK(starttagloop);
1281 case NOBR: {
1282 reconstructTheActiveFormattingElements();
1283 if (nsHtml5TreeBuilder::NOT_FOUND_ON_STACK !=
1284 findLastInScope(nsGkAtoms::nobr)) {
1285 errFooSeenWhenFooOpen(name);
1286 adoptionAgencyEndTag(nsGkAtoms::nobr);
1287 reconstructTheActiveFormattingElements();
1289 appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
1290 attributes);
1291 attributes = nullptr;
1292 NS_HTML5_BREAK(starttagloop);
1294 case BUTTON: {
1295 eltPos = findLastInScope(name);
1296 if (eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1297 errFooSeenWhenFooOpen(name);
1298 generateImpliedEndTags();
1299 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
1300 errUnclosedElementsImplied(eltPos, name);
1302 while (currentPtr >= eltPos) {
1303 pop();
1305 NS_HTML5_CONTINUE(starttagloop);
1306 } else {
1307 reconstructTheActiveFormattingElements();
1308 appendToCurrentNodeAndPushElementMayFoster(
1309 elementName, attributes, formPointer);
1310 attributes = nullptr;
1311 NS_HTML5_BREAK(starttagloop);
1314 case OBJECT: {
1315 reconstructTheActiveFormattingElements();
1316 appendToCurrentNodeAndPushElementMayFoster(
1317 elementName, attributes, formPointer);
1318 insertMarker();
1319 attributes = nullptr;
1320 NS_HTML5_BREAK(starttagloop);
1322 case MARQUEE_OR_APPLET: {
1323 reconstructTheActiveFormattingElements();
1324 appendToCurrentNodeAndPushElementMayFoster(elementName,
1325 attributes);
1326 insertMarker();
1327 attributes = nullptr;
1328 NS_HTML5_BREAK(starttagloop);
1330 case TABLE: {
1331 if (!quirks) {
1332 implicitlyCloseP();
1334 appendToCurrentNodeAndPushElementMayFoster(elementName,
1335 attributes);
1336 mode = IN_TABLE;
1337 attributes = nullptr;
1338 NS_HTML5_BREAK(starttagloop);
1340 case BR:
1341 case EMBED:
1342 case AREA_OR_WBR:
1343 case KEYGEN: {
1344 reconstructTheActiveFormattingElements();
1345 [[fallthrough]];
1347 #ifdef ENABLE_VOID_MENUITEM
1348 case MENUITEM:
1349 #endif
1350 case PARAM_OR_SOURCE_OR_TRACK: {
1351 appendVoidElementToCurrentMayFoster(elementName, attributes);
1352 selfClosing = false;
1353 attributes = nullptr;
1354 NS_HTML5_BREAK(starttagloop);
1356 case HR: {
1357 implicitlyCloseP();
1358 appendVoidElementToCurrentMayFoster(elementName, attributes);
1359 selfClosing = false;
1360 attributes = nullptr;
1361 NS_HTML5_BREAK(starttagloop);
1363 case IMAGE: {
1364 errImage();
1365 elementName = nsHtml5ElementName::ELT_IMG;
1366 NS_HTML5_CONTINUE(starttagloop);
1368 case IMG:
1369 case INPUT: {
1370 reconstructTheActiveFormattingElements();
1371 appendVoidElementToCurrentMayFoster(elementName, attributes,
1372 formPointer);
1373 selfClosing = false;
1374 attributes = nullptr;
1375 NS_HTML5_BREAK(starttagloop);
1377 case TEXTAREA: {
1378 appendToCurrentNodeAndPushElementMayFoster(
1379 elementName, attributes, formPointer);
1380 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
1381 elementName);
1382 originalMode = mode;
1383 mode = TEXT;
1384 needToDropLF = true;
1385 attributes = nullptr;
1386 NS_HTML5_BREAK(starttagloop);
1388 case XMP: {
1389 implicitlyCloseP();
1390 reconstructTheActiveFormattingElements();
1391 appendToCurrentNodeAndPushElementMayFoster(elementName,
1392 attributes);
1393 originalMode = mode;
1394 mode = TEXT;
1395 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1396 elementName);
1397 attributes = nullptr;
1398 NS_HTML5_BREAK(starttagloop);
1400 case NOSCRIPT: {
1401 if (!scriptingEnabled) {
1402 reconstructTheActiveFormattingElements();
1403 appendToCurrentNodeAndPushElementMayFoster(elementName,
1404 attributes);
1405 attributes = nullptr;
1406 NS_HTML5_BREAK(starttagloop);
1408 [[fallthrough]];
1410 case NOFRAMES:
1411 case IFRAME:
1412 case NOEMBED: {
1413 startTagGenericRawText(elementName, attributes);
1414 attributes = nullptr;
1415 NS_HTML5_BREAK(starttagloop);
1417 case SELECT: {
1418 reconstructTheActiveFormattingElements();
1419 appendToCurrentNodeAndPushElementMayFoster(
1420 elementName, attributes, formPointer);
1421 switch (mode) {
1422 case IN_TABLE:
1423 case IN_CAPTION:
1424 case IN_COLUMN_GROUP:
1425 case IN_TABLE_BODY:
1426 case IN_ROW:
1427 case IN_CELL: {
1428 mode = IN_SELECT_IN_TABLE;
1429 break;
1431 default: {
1432 mode = IN_SELECT;
1433 break;
1436 attributes = nullptr;
1437 NS_HTML5_BREAK(starttagloop);
1439 case OPTGROUP:
1440 case OPTION: {
1441 if (isCurrent(nsGkAtoms::option)) {
1442 pop();
1444 reconstructTheActiveFormattingElements();
1445 appendToCurrentNodeAndPushElementMayFoster(elementName,
1446 attributes);
1447 attributes = nullptr;
1448 NS_HTML5_BREAK(starttagloop);
1450 case RB_OR_RTC: {
1451 eltPos = findLastInScope(nsGkAtoms::ruby);
1452 if (eltPos != NOT_FOUND_ON_STACK) {
1453 generateImpliedEndTags();
1455 if (eltPos != currentPtr) {
1456 if (eltPos == NOT_FOUND_ON_STACK) {
1457 errStartTagSeenWithoutRuby(name);
1458 } else {
1459 errUnclosedChildrenInRuby();
1462 appendToCurrentNodeAndPushElementMayFoster(elementName,
1463 attributes);
1464 attributes = nullptr;
1465 NS_HTML5_BREAK(starttagloop);
1467 case RT_OR_RP: {
1468 eltPos = findLastInScope(nsGkAtoms::ruby);
1469 if (eltPos != NOT_FOUND_ON_STACK) {
1470 generateImpliedEndTagsExceptFor(nsGkAtoms::rtc);
1472 if (eltPos != currentPtr) {
1473 if (!isCurrent(nsGkAtoms::rtc)) {
1474 if (eltPos == NOT_FOUND_ON_STACK) {
1475 errStartTagSeenWithoutRuby(name);
1476 } else {
1477 errUnclosedChildrenInRuby();
1481 appendToCurrentNodeAndPushElementMayFoster(elementName,
1482 attributes);
1483 attributes = nullptr;
1484 NS_HTML5_BREAK(starttagloop);
1486 case MATH: {
1487 reconstructTheActiveFormattingElements();
1488 attributes->adjustForMath();
1489 if (selfClosing) {
1490 appendVoidElementToCurrentMayFosterMathML(elementName,
1491 attributes);
1492 selfClosing = false;
1493 } else {
1494 appendToCurrentNodeAndPushElementMayFosterMathML(elementName,
1495 attributes);
1497 attributes = nullptr;
1498 NS_HTML5_BREAK(starttagloop);
1500 case SVG: {
1501 reconstructTheActiveFormattingElements();
1502 attributes->adjustForSvg();
1503 if (selfClosing) {
1504 appendVoidElementToCurrentMayFosterSVG(elementName, attributes);
1505 selfClosing = false;
1506 } else {
1507 appendToCurrentNodeAndPushElementMayFosterSVG(elementName,
1508 attributes);
1510 attributes = nullptr;
1511 NS_HTML5_BREAK(starttagloop);
1513 case CAPTION:
1514 case COL:
1515 case COLGROUP:
1516 case TBODY_OR_THEAD_OR_TFOOT:
1517 case TR:
1518 case TD_OR_TH:
1519 case FRAME:
1520 case FRAMESET:
1521 case HEAD: {
1522 errStrayStartTag(name);
1523 NS_HTML5_BREAK(starttagloop);
1525 case OUTPUT: {
1526 reconstructTheActiveFormattingElements();
1527 appendToCurrentNodeAndPushElementMayFoster(
1528 elementName, attributes, formPointer);
1529 attributes = nullptr;
1530 NS_HTML5_BREAK(starttagloop);
1532 default: {
1533 reconstructTheActiveFormattingElements();
1534 appendToCurrentNodeAndPushElementMayFoster(elementName,
1535 attributes);
1536 attributes = nullptr;
1537 NS_HTML5_BREAK(starttagloop);
1541 inbodyloop_end:;
1542 [[fallthrough]];
1544 case IN_HEAD: {
1545 for (;;) {
1546 switch (group) {
1547 case HTML: {
1548 errStrayStartTag(name);
1549 if (!fragment && !isTemplateContents()) {
1550 addAttributesToHtml(attributes);
1551 attributes = nullptr;
1553 NS_HTML5_BREAK(starttagloop);
1555 case BASE:
1556 case LINK_OR_BASEFONT_OR_BGSOUND: {
1557 appendVoidElementToCurrentMayFoster(elementName, attributes);
1558 selfClosing = false;
1559 attributes = nullptr;
1560 NS_HTML5_BREAK(starttagloop);
1562 case META: {
1563 NS_HTML5_BREAK(inheadloop);
1565 case TITLE: {
1566 startTagTitleInHead(elementName, attributes);
1567 attributes = nullptr;
1568 NS_HTML5_BREAK(starttagloop);
1570 case NOSCRIPT: {
1571 if (scriptingEnabled) {
1572 appendToCurrentNodeAndPushElement(elementName, attributes);
1573 originalMode = mode;
1574 mode = TEXT;
1575 tokenizer->setStateAndEndTagExpectation(
1576 nsHtml5Tokenizer::RAWTEXT, elementName);
1577 } else {
1578 appendToCurrentNodeAndPushElementMayFoster(elementName,
1579 attributes);
1580 mode = IN_HEAD_NOSCRIPT;
1582 attributes = nullptr;
1583 NS_HTML5_BREAK(starttagloop);
1585 case SCRIPT: {
1586 startTagScriptInHead(elementName, attributes);
1587 attributes = nullptr;
1588 NS_HTML5_BREAK(starttagloop);
1590 case STYLE:
1591 case NOFRAMES: {
1592 startTagGenericRawText(elementName, attributes);
1593 attributes = nullptr;
1594 NS_HTML5_BREAK(starttagloop);
1596 case HEAD: {
1597 errFooSeenWhenFooOpen(name);
1598 NS_HTML5_BREAK(starttagloop);
1600 case TEMPLATE: {
1601 startTagTemplateInHead(elementName, attributes);
1602 attributes = nullptr;
1603 NS_HTML5_BREAK(starttagloop);
1605 default: {
1606 pop();
1607 mode = AFTER_HEAD;
1608 NS_HTML5_CONTINUE(starttagloop);
1612 inheadloop_end:;
1613 [[fallthrough]];
1615 case IN_HEAD_NOSCRIPT: {
1616 switch (group) {
1617 case HTML: {
1618 errStrayStartTag(name);
1619 if (!fragment && !isTemplateContents()) {
1620 addAttributesToHtml(attributes);
1621 attributes = nullptr;
1623 NS_HTML5_BREAK(starttagloop);
1625 case LINK_OR_BASEFONT_OR_BGSOUND: {
1626 appendVoidElementToCurrentMayFoster(elementName, attributes);
1627 selfClosing = false;
1628 attributes = nullptr;
1629 NS_HTML5_BREAK(starttagloop);
1631 case META: {
1632 checkMetaCharset(attributes);
1633 appendVoidElementToCurrentMayFoster(elementName, attributes);
1634 selfClosing = false;
1635 attributes = nullptr;
1636 NS_HTML5_BREAK(starttagloop);
1638 case STYLE:
1639 case NOFRAMES: {
1640 appendToCurrentNodeAndPushElement(elementName, attributes);
1641 originalMode = mode;
1642 mode = TEXT;
1643 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1644 elementName);
1645 attributes = nullptr;
1646 NS_HTML5_BREAK(starttagloop);
1648 case HEAD: {
1649 errFooSeenWhenFooOpen(name);
1650 NS_HTML5_BREAK(starttagloop);
1652 case NOSCRIPT: {
1653 errFooSeenWhenFooOpen(name);
1654 NS_HTML5_BREAK(starttagloop);
1656 default: {
1657 errBadStartTagInNoscriptInHead(name);
1658 pop();
1659 mode = IN_HEAD;
1660 continue;
1664 case IN_COLUMN_GROUP: {
1665 switch (group) {
1666 case HTML: {
1667 errStrayStartTag(name);
1668 if (!fragment && !isTemplateContents()) {
1669 addAttributesToHtml(attributes);
1670 attributes = nullptr;
1672 NS_HTML5_BREAK(starttagloop);
1674 case COL: {
1675 appendVoidElementToCurrentMayFoster(elementName, attributes);
1676 selfClosing = false;
1677 attributes = nullptr;
1678 NS_HTML5_BREAK(starttagloop);
1680 case TEMPLATE: {
1681 startTagTemplateInHead(elementName, attributes);
1682 attributes = nullptr;
1683 NS_HTML5_BREAK(starttagloop);
1685 default: {
1686 if (!currentPtr || stack[currentPtr]->getGroup() == TEMPLATE) {
1687 MOZ_ASSERT(fragment || isTemplateContents());
1688 errGarbageInColgroup();
1689 NS_HTML5_BREAK(starttagloop);
1691 pop();
1692 mode = IN_TABLE;
1693 continue;
1697 case IN_SELECT_IN_TABLE: {
1698 switch (group) {
1699 case CAPTION:
1700 case TBODY_OR_THEAD_OR_TFOOT:
1701 case TR:
1702 case TD_OR_TH:
1703 case TABLE: {
1704 errStartTagWithSelectOpen(name);
1705 eltPos = findLastInTableScope(nsGkAtoms::select);
1706 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1707 MOZ_ASSERT(fragment);
1708 NS_HTML5_BREAK(starttagloop);
1710 while (currentPtr >= eltPos) {
1711 pop();
1713 resetTheInsertionMode();
1714 continue;
1716 default:; // fall through
1718 [[fallthrough]];
1720 case IN_SELECT: {
1721 switch (group) {
1722 case HTML: {
1723 errStrayStartTag(name);
1724 if (!fragment) {
1725 addAttributesToHtml(attributes);
1726 attributes = nullptr;
1728 NS_HTML5_BREAK(starttagloop);
1730 case OPTION: {
1731 if (isCurrent(nsGkAtoms::option)) {
1732 pop();
1734 appendToCurrentNodeAndPushElement(elementName, attributes);
1735 attributes = nullptr;
1736 NS_HTML5_BREAK(starttagloop);
1738 case OPTGROUP: {
1739 if (isCurrent(nsGkAtoms::option)) {
1740 pop();
1742 if (isCurrent(nsGkAtoms::optgroup)) {
1743 pop();
1745 appendToCurrentNodeAndPushElement(elementName, attributes);
1746 attributes = nullptr;
1747 NS_HTML5_BREAK(starttagloop);
1749 case SELECT: {
1750 errStartSelectWhereEndSelectExpected();
1751 eltPos = findLastInTableScope(name);
1752 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1753 MOZ_ASSERT(fragment);
1754 errNoSelectInTableScope();
1755 NS_HTML5_BREAK(starttagloop);
1756 } else {
1757 while (currentPtr >= eltPos) {
1758 pop();
1760 resetTheInsertionMode();
1761 NS_HTML5_BREAK(starttagloop);
1764 case INPUT:
1765 case TEXTAREA: {
1766 errStartTagWithSelectOpen(name);
1767 eltPos = findLastInTableScope(nsGkAtoms::select);
1768 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1769 MOZ_ASSERT(fragment);
1770 NS_HTML5_BREAK(starttagloop);
1772 while (currentPtr >= eltPos) {
1773 pop();
1775 resetTheInsertionMode();
1776 continue;
1778 case SCRIPT: {
1779 startTagScriptInHead(elementName, attributes);
1780 attributes = nullptr;
1781 NS_HTML5_BREAK(starttagloop);
1783 case TEMPLATE: {
1784 startTagTemplateInHead(elementName, attributes);
1785 attributes = nullptr;
1786 NS_HTML5_BREAK(starttagloop);
1788 default: {
1789 errStrayStartTag(name);
1790 NS_HTML5_BREAK(starttagloop);
1794 case AFTER_BODY: {
1795 switch (group) {
1796 case HTML: {
1797 errStrayStartTag(name);
1798 if (!fragment && !isTemplateContents()) {
1799 addAttributesToHtml(attributes);
1800 attributes = nullptr;
1802 NS_HTML5_BREAK(starttagloop);
1804 default: {
1805 errStrayStartTag(name);
1806 mode = framesetOk ? FRAMESET_OK : IN_BODY;
1807 continue;
1811 case IN_FRAMESET: {
1812 switch (group) {
1813 case FRAMESET: {
1814 appendToCurrentNodeAndPushElement(elementName, attributes);
1815 attributes = nullptr;
1816 NS_HTML5_BREAK(starttagloop);
1818 case FRAME: {
1819 appendVoidElementToCurrentMayFoster(elementName, attributes);
1820 selfClosing = false;
1821 attributes = nullptr;
1822 NS_HTML5_BREAK(starttagloop);
1824 default:; // fall through
1826 [[fallthrough]];
1828 case AFTER_FRAMESET: {
1829 switch (group) {
1830 case HTML: {
1831 errStrayStartTag(name);
1832 if (!fragment && !isTemplateContents()) {
1833 addAttributesToHtml(attributes);
1834 attributes = nullptr;
1836 NS_HTML5_BREAK(starttagloop);
1838 case NOFRAMES: {
1839 appendToCurrentNodeAndPushElement(elementName, attributes);
1840 originalMode = mode;
1841 mode = TEXT;
1842 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1843 elementName);
1844 attributes = nullptr;
1845 NS_HTML5_BREAK(starttagloop);
1847 default: {
1848 errStrayStartTag(name);
1849 NS_HTML5_BREAK(starttagloop);
1853 case INITIAL: {
1854 errStartTagWithoutDoctype();
1855 documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
1856 mode = BEFORE_HTML;
1857 continue;
1859 case BEFORE_HTML: {
1860 switch (group) {
1861 case HTML: {
1862 if (attributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
1863 appendHtmlElementToDocumentAndPush();
1864 } else {
1865 appendHtmlElementToDocumentAndPush(attributes);
1867 mode = BEFORE_HEAD;
1868 attributes = nullptr;
1869 NS_HTML5_BREAK(starttagloop);
1871 default: {
1872 appendHtmlElementToDocumentAndPush();
1873 mode = BEFORE_HEAD;
1874 continue;
1878 case BEFORE_HEAD: {
1879 switch (group) {
1880 case HTML: {
1881 errStrayStartTag(name);
1882 if (!fragment && !isTemplateContents()) {
1883 addAttributesToHtml(attributes);
1884 attributes = nullptr;
1886 NS_HTML5_BREAK(starttagloop);
1888 case HEAD: {
1889 appendToCurrentNodeAndPushHeadElement(attributes);
1890 mode = IN_HEAD;
1891 attributes = nullptr;
1892 NS_HTML5_BREAK(starttagloop);
1894 default: {
1895 appendToCurrentNodeAndPushHeadElement(
1896 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
1897 mode = IN_HEAD;
1898 continue;
1902 case AFTER_HEAD: {
1903 switch (group) {
1904 case HTML: {
1905 errStrayStartTag(name);
1906 if (!fragment && !isTemplateContents()) {
1907 addAttributesToHtml(attributes);
1908 attributes = nullptr;
1910 NS_HTML5_BREAK(starttagloop);
1912 case BODY: {
1913 if (!attributes->getLength()) {
1914 appendToCurrentNodeAndPushBodyElement();
1915 } else {
1916 appendToCurrentNodeAndPushBodyElement(attributes);
1918 framesetOk = false;
1919 mode = IN_BODY;
1920 attributes = nullptr;
1921 NS_HTML5_BREAK(starttagloop);
1923 case FRAMESET: {
1924 appendToCurrentNodeAndPushElement(elementName, attributes);
1925 mode = IN_FRAMESET;
1926 attributes = nullptr;
1927 NS_HTML5_BREAK(starttagloop);
1929 case TEMPLATE: {
1930 errFooBetweenHeadAndBody(name);
1931 pushHeadPointerOntoStack();
1932 nsHtml5StackNode* headOnStack = stack[currentPtr];
1933 startTagTemplateInHead(elementName, attributes);
1934 removeFromStack(headOnStack);
1935 attributes = nullptr;
1936 NS_HTML5_BREAK(starttagloop);
1938 case BASE:
1939 case LINK_OR_BASEFONT_OR_BGSOUND: {
1940 errFooBetweenHeadAndBody(name);
1941 pushHeadPointerOntoStack();
1942 appendVoidElementToCurrentMayFoster(elementName, attributes);
1943 selfClosing = false;
1944 pop();
1945 attributes = nullptr;
1946 NS_HTML5_BREAK(starttagloop);
1948 case META: {
1949 errFooBetweenHeadAndBody(name);
1950 checkMetaCharset(attributes);
1951 pushHeadPointerOntoStack();
1952 appendVoidElementToCurrentMayFoster(elementName, attributes);
1953 selfClosing = false;
1954 pop();
1955 attributes = nullptr;
1956 NS_HTML5_BREAK(starttagloop);
1958 case SCRIPT: {
1959 errFooBetweenHeadAndBody(name);
1960 pushHeadPointerOntoStack();
1961 appendToCurrentNodeAndPushElement(elementName, attributes);
1962 originalMode = mode;
1963 mode = TEXT;
1964 tokenizer->setStateAndEndTagExpectation(
1965 nsHtml5Tokenizer::SCRIPT_DATA, elementName);
1966 attributes = nullptr;
1967 NS_HTML5_BREAK(starttagloop);
1969 case STYLE:
1970 case NOFRAMES: {
1971 errFooBetweenHeadAndBody(name);
1972 pushHeadPointerOntoStack();
1973 appendToCurrentNodeAndPushElement(elementName, attributes);
1974 originalMode = mode;
1975 mode = TEXT;
1976 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1977 elementName);
1978 attributes = nullptr;
1979 NS_HTML5_BREAK(starttagloop);
1981 case TITLE: {
1982 errFooBetweenHeadAndBody(name);
1983 pushHeadPointerOntoStack();
1984 appendToCurrentNodeAndPushElement(elementName, attributes);
1985 originalMode = mode;
1986 mode = TEXT;
1987 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
1988 elementName);
1989 attributes = nullptr;
1990 NS_HTML5_BREAK(starttagloop);
1992 case HEAD: {
1993 errStrayStartTag(name);
1994 NS_HTML5_BREAK(starttagloop);
1996 default: {
1997 appendToCurrentNodeAndPushBodyElement();
1998 mode = FRAMESET_OK;
1999 continue;
2003 case AFTER_AFTER_BODY: {
2004 switch (group) {
2005 case HTML: {
2006 errStrayStartTag(name);
2007 if (!fragment && !isTemplateContents()) {
2008 addAttributesToHtml(attributes);
2009 attributes = nullptr;
2011 NS_HTML5_BREAK(starttagloop);
2013 default: {
2014 errStrayStartTag(name);
2016 mode = framesetOk ? FRAMESET_OK : IN_BODY;
2017 continue;
2021 case AFTER_AFTER_FRAMESET: {
2022 switch (group) {
2023 case HTML: {
2024 errStrayStartTag(name);
2025 if (!fragment && !isTemplateContents()) {
2026 addAttributesToHtml(attributes);
2027 attributes = nullptr;
2029 NS_HTML5_BREAK(starttagloop);
2031 case NOFRAMES: {
2032 startTagGenericRawText(elementName, attributes);
2033 attributes = nullptr;
2034 NS_HTML5_BREAK(starttagloop);
2036 default: {
2037 errStrayStartTag(name);
2038 NS_HTML5_BREAK(starttagloop);
2042 case TEXT: {
2043 MOZ_ASSERT(false);
2044 NS_HTML5_BREAK(starttagloop);
2048 starttagloop_end:;
2049 if (selfClosing) {
2050 errSelfClosing();
2052 if (!mBuilder && attributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
2053 delete attributes;
2057 void nsHtml5TreeBuilder::startTagTitleInHead(
2058 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2059 appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
2060 originalMode = mode;
2061 mode = TEXT;
2062 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
2063 elementName);
2066 void nsHtml5TreeBuilder::startTagGenericRawText(
2067 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2068 appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
2069 originalMode = mode;
2070 mode = TEXT;
2071 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
2072 elementName);
2075 void nsHtml5TreeBuilder::startTagScriptInHead(
2076 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2077 appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
2078 originalMode = mode;
2079 mode = TEXT;
2080 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::SCRIPT_DATA,
2081 elementName);
2084 void nsHtml5TreeBuilder::startTagTemplateInHead(
2085 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2086 appendToCurrentNodeAndPushElement(elementName, attributes);
2087 insertMarker();
2088 framesetOk = false;
2089 originalMode = mode;
2090 mode = IN_TEMPLATE;
2091 pushTemplateMode(IN_TEMPLATE);
2094 bool nsHtml5TreeBuilder::isTemplateContents() {
2095 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK !=
2096 findLast(nsGkAtoms::_template);
2099 bool nsHtml5TreeBuilder::isTemplateModeStackEmpty() {
2100 return templateModePtr == -1;
2103 bool nsHtml5TreeBuilder::isSpecialParentInForeign(nsHtml5StackNode* stackNode) {
2104 int32_t ns = stackNode->ns;
2105 return (kNameSpaceID_XHTML == ns) || (stackNode->isHtmlIntegrationPoint()) ||
2106 ((kNameSpaceID_MathML == ns) &&
2107 (stackNode->getGroup() == MI_MO_MN_MS_MTEXT));
2110 nsHtml5String nsHtml5TreeBuilder::extractCharsetFromContent(
2111 nsHtml5String attributeValue, nsHtml5TreeBuilder* tb) {
2112 int32_t charsetState = CHARSET_INITIAL;
2113 int32_t start = -1;
2114 int32_t end = -1;
2115 autoJArray<char16_t, int32_t> buffer =
2116 nsHtml5Portability::newCharArrayFromString(attributeValue);
2117 for (int32_t i = 0; i < buffer.length; i++) {
2118 char16_t c = buffer[i];
2119 switch (charsetState) {
2120 case CHARSET_INITIAL: {
2121 switch (c) {
2122 case 'c':
2123 case 'C': {
2124 charsetState = CHARSET_C;
2125 continue;
2127 default: {
2128 continue;
2132 case CHARSET_C: {
2133 switch (c) {
2134 case 'h':
2135 case 'H': {
2136 charsetState = CHARSET_H;
2137 continue;
2139 default: {
2140 charsetState = CHARSET_INITIAL;
2141 continue;
2145 case CHARSET_H: {
2146 switch (c) {
2147 case 'a':
2148 case 'A': {
2149 charsetState = CHARSET_A;
2150 continue;
2152 default: {
2153 charsetState = CHARSET_INITIAL;
2154 continue;
2158 case CHARSET_A: {
2159 switch (c) {
2160 case 'r':
2161 case 'R': {
2162 charsetState = CHARSET_R;
2163 continue;
2165 default: {
2166 charsetState = CHARSET_INITIAL;
2167 continue;
2171 case CHARSET_R: {
2172 switch (c) {
2173 case 's':
2174 case 'S': {
2175 charsetState = CHARSET_S;
2176 continue;
2178 default: {
2179 charsetState = CHARSET_INITIAL;
2180 continue;
2184 case CHARSET_S: {
2185 switch (c) {
2186 case 'e':
2187 case 'E': {
2188 charsetState = CHARSET_E;
2189 continue;
2191 default: {
2192 charsetState = CHARSET_INITIAL;
2193 continue;
2197 case CHARSET_E: {
2198 switch (c) {
2199 case 't':
2200 case 'T': {
2201 charsetState = CHARSET_T;
2202 continue;
2204 default: {
2205 charsetState = CHARSET_INITIAL;
2206 continue;
2210 case CHARSET_T: {
2211 switch (c) {
2212 case '\t':
2213 case '\n':
2214 case '\f':
2215 case '\r':
2216 case ' ': {
2217 continue;
2219 case '=': {
2220 charsetState = CHARSET_EQUALS;
2221 continue;
2223 default: {
2224 return nullptr;
2228 case CHARSET_EQUALS: {
2229 switch (c) {
2230 case '\t':
2231 case '\n':
2232 case '\f':
2233 case '\r':
2234 case ' ': {
2235 continue;
2237 case '\'': {
2238 start = i + 1;
2239 charsetState = CHARSET_SINGLE_QUOTED;
2240 continue;
2242 case '\"': {
2243 start = i + 1;
2244 charsetState = CHARSET_DOUBLE_QUOTED;
2245 continue;
2247 default: {
2248 start = i;
2249 charsetState = CHARSET_UNQUOTED;
2250 continue;
2254 case CHARSET_SINGLE_QUOTED: {
2255 switch (c) {
2256 case '\'': {
2257 end = i;
2258 NS_HTML5_BREAK(charsetloop);
2260 default: {
2261 continue;
2265 case CHARSET_DOUBLE_QUOTED: {
2266 switch (c) {
2267 case '\"': {
2268 end = i;
2269 NS_HTML5_BREAK(charsetloop);
2271 default: {
2272 continue;
2276 case CHARSET_UNQUOTED: {
2277 switch (c) {
2278 case '\t':
2279 case '\n':
2280 case '\f':
2281 case '\r':
2282 case ' ':
2283 case ';': {
2284 end = i;
2285 NS_HTML5_BREAK(charsetloop);
2287 default: {
2288 continue;
2294 charsetloop_end:;
2295 if (start != -1) {
2296 if (end == -1) {
2297 if (charsetState == CHARSET_UNQUOTED) {
2298 end = buffer.length;
2299 } else {
2300 return nullptr;
2303 return nsHtml5Portability::newStringFromBuffer(buffer, start, end - start,
2304 tb, false);
2306 return nullptr;
2309 void nsHtml5TreeBuilder::checkMetaCharset(nsHtml5HtmlAttributes* attributes) {
2310 nsHtml5String charset =
2311 attributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
2312 if (charset) {
2313 if (tokenizer->internalEncodingDeclaration(charset)) {
2314 requestSuspension();
2315 return;
2317 return;
2319 if (!nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
2320 "content-type",
2321 attributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) {
2322 return;
2324 nsHtml5String content =
2325 attributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
2326 if (content) {
2327 nsHtml5String extract =
2328 nsHtml5TreeBuilder::extractCharsetFromContent(content, this);
2329 if (extract) {
2330 if (tokenizer->internalEncodingDeclaration(extract)) {
2331 requestSuspension();
2334 extract.Release();
2338 void nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) {
2339 flushCharacters();
2340 needToDropLF = false;
2341 int32_t eltPos;
2342 int32_t group = elementName->getGroup();
2343 nsAtom* name = elementName->getName();
2344 for (;;) {
2345 if (isInForeign()) {
2346 if (stack[currentPtr]->name != name) {
2347 if (!currentPtr) {
2348 errStrayEndTag(name);
2349 } else {
2350 errEndTagDidNotMatchCurrentOpenElement(name,
2351 stack[currentPtr]->popName);
2354 eltPos = currentPtr;
2355 int32_t origPos = currentPtr;
2356 for (;;) {
2357 if (!eltPos) {
2358 MOZ_ASSERT(fragment,
2359 "We can get this close to the root of the stack in "
2360 "foreign content only in the fragment case.");
2361 NS_HTML5_BREAK(endtagloop);
2363 if (stack[eltPos]->name == name) {
2364 while (currentPtr >= eltPos) {
2365 popForeign(origPos, eltPos);
2367 NS_HTML5_BREAK(endtagloop);
2369 if (stack[--eltPos]->ns == kNameSpaceID_XHTML) {
2370 break;
2374 switch (mode) {
2375 case IN_TEMPLATE: {
2376 switch (group) {
2377 case TEMPLATE: {
2378 break;
2380 default: {
2381 errStrayEndTag(name);
2382 NS_HTML5_BREAK(endtagloop);
2385 [[fallthrough]];
2387 case IN_ROW: {
2388 switch (group) {
2389 case TR: {
2390 eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
2391 if (!eltPos) {
2392 MOZ_ASSERT(fragment || isTemplateContents());
2393 errNoTableRowToClose();
2394 NS_HTML5_BREAK(endtagloop);
2396 clearStackBackTo(eltPos);
2397 pop();
2398 mode = IN_TABLE_BODY;
2399 NS_HTML5_BREAK(endtagloop);
2401 case TABLE: {
2402 eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
2403 if (!eltPos) {
2404 MOZ_ASSERT(fragment || isTemplateContents());
2405 errNoTableRowToClose();
2406 NS_HTML5_BREAK(endtagloop);
2408 clearStackBackTo(eltPos);
2409 pop();
2410 mode = IN_TABLE_BODY;
2411 continue;
2413 case TBODY_OR_THEAD_OR_TFOOT: {
2414 if (findLastInTableScope(name) ==
2415 nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2416 errStrayEndTag(name);
2417 NS_HTML5_BREAK(endtagloop);
2419 eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
2420 if (!eltPos) {
2421 MOZ_ASSERT(fragment || isTemplateContents());
2422 errNoTableRowToClose();
2423 NS_HTML5_BREAK(endtagloop);
2425 clearStackBackTo(eltPos);
2426 pop();
2427 mode = IN_TABLE_BODY;
2428 continue;
2430 case BODY:
2431 case CAPTION:
2432 case COL:
2433 case COLGROUP:
2434 case HTML:
2435 case TD_OR_TH: {
2436 errStrayEndTag(name);
2437 NS_HTML5_BREAK(endtagloop);
2439 default:; // fall through
2441 [[fallthrough]];
2443 case IN_TABLE_BODY: {
2444 switch (group) {
2445 case TBODY_OR_THEAD_OR_TFOOT: {
2446 eltPos = findLastOrRoot(name);
2447 if (!eltPos) {
2448 errStrayEndTag(name);
2449 NS_HTML5_BREAK(endtagloop);
2451 clearStackBackTo(eltPos);
2452 pop();
2453 mode = IN_TABLE;
2454 NS_HTML5_BREAK(endtagloop);
2456 case TABLE: {
2457 eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
2458 if (!eltPos || stack[eltPos]->getGroup() == TEMPLATE) {
2459 MOZ_ASSERT(fragment || isTemplateContents());
2460 errStrayEndTag(name);
2461 NS_HTML5_BREAK(endtagloop);
2463 clearStackBackTo(eltPos);
2464 pop();
2465 mode = IN_TABLE;
2466 continue;
2468 case BODY:
2469 case CAPTION:
2470 case COL:
2471 case COLGROUP:
2472 case HTML:
2473 case TD_OR_TH:
2474 case TR: {
2475 errStrayEndTag(name);
2476 NS_HTML5_BREAK(endtagloop);
2478 default:; // fall through
2480 [[fallthrough]];
2482 case IN_TABLE: {
2483 switch (group) {
2484 case TABLE: {
2485 eltPos = findLast(nsGkAtoms::table);
2486 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2487 MOZ_ASSERT(fragment || isTemplateContents());
2488 errStrayEndTag(name);
2489 NS_HTML5_BREAK(endtagloop);
2491 while (currentPtr >= eltPos) {
2492 pop();
2494 resetTheInsertionMode();
2495 NS_HTML5_BREAK(endtagloop);
2497 case BODY:
2498 case CAPTION:
2499 case COL:
2500 case COLGROUP:
2501 case HTML:
2502 case TBODY_OR_THEAD_OR_TFOOT:
2503 case TD_OR_TH:
2504 case TR: {
2505 errStrayEndTag(name);
2506 NS_HTML5_BREAK(endtagloop);
2508 case TEMPLATE: {
2509 break;
2511 default: {
2512 errStrayEndTag(name);
2515 [[fallthrough]];
2517 case IN_CAPTION: {
2518 switch (group) {
2519 case CAPTION: {
2520 eltPos = findLastInTableScope(nsGkAtoms::caption);
2521 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2522 NS_HTML5_BREAK(endtagloop);
2524 generateImpliedEndTags();
2525 if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
2526 errUnclosedElements(eltPos, name);
2528 while (currentPtr >= eltPos) {
2529 pop();
2531 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
2532 mode = IN_TABLE;
2533 NS_HTML5_BREAK(endtagloop);
2535 case TABLE: {
2536 eltPos = findLastInTableScope(nsGkAtoms::caption);
2537 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2538 MOZ_ASSERT(fragment || isTemplateContents());
2539 errStrayEndTag(name);
2540 NS_HTML5_BREAK(endtagloop);
2542 generateImpliedEndTags();
2543 if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
2544 errUnclosedElements(eltPos, name);
2546 while (currentPtr >= eltPos) {
2547 pop();
2549 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
2550 mode = IN_TABLE;
2551 continue;
2553 case BODY:
2554 case COL:
2555 case COLGROUP:
2556 case HTML:
2557 case TBODY_OR_THEAD_OR_TFOOT:
2558 case TD_OR_TH:
2559 case TR: {
2560 errStrayEndTag(name);
2561 NS_HTML5_BREAK(endtagloop);
2563 default:; // fall through
2565 [[fallthrough]];
2567 case IN_CELL: {
2568 switch (group) {
2569 case TD_OR_TH: {
2570 eltPos = findLastInTableScope(name);
2571 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2572 errStrayEndTag(name);
2573 NS_HTML5_BREAK(endtagloop);
2575 generateImpliedEndTags();
2576 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2577 errUnclosedElements(eltPos, name);
2579 while (currentPtr >= eltPos) {
2580 pop();
2582 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
2583 mode = IN_ROW;
2584 NS_HTML5_BREAK(endtagloop);
2586 case TABLE:
2587 case TBODY_OR_THEAD_OR_TFOOT:
2588 case TR: {
2589 if (findLastInTableScope(name) ==
2590 nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2591 MOZ_ASSERT(name == nsGkAtoms::tbody || name == nsGkAtoms::tfoot ||
2592 name == nsGkAtoms::thead || fragment ||
2593 isTemplateContents());
2594 errStrayEndTag(name);
2595 NS_HTML5_BREAK(endtagloop);
2597 closeTheCell(findLastInTableScopeTdTh());
2598 continue;
2600 case BODY:
2601 case CAPTION:
2602 case COL:
2603 case COLGROUP:
2604 case HTML: {
2605 errStrayEndTag(name);
2606 NS_HTML5_BREAK(endtagloop);
2608 default:; // fall through
2610 [[fallthrough]];
2612 case FRAMESET_OK:
2613 case IN_BODY: {
2614 switch (group) {
2615 case BODY: {
2616 if (!isSecondOnStackBody()) {
2617 MOZ_ASSERT(fragment || isTemplateContents());
2618 errStrayEndTag(name);
2619 NS_HTML5_BREAK(endtagloop);
2621 MOZ_ASSERT(currentPtr >= 1);
2622 if (MOZ_UNLIKELY(mViewSource)) {
2623 for (int32_t i = 2; i <= currentPtr; i++) {
2624 switch (stack[i]->getGroup()) {
2625 case DD_OR_DT:
2626 case LI:
2627 case OPTGROUP:
2628 case OPTION:
2629 case P:
2630 case RB_OR_RTC:
2631 case RT_OR_RP:
2632 case TD_OR_TH:
2633 case TBODY_OR_THEAD_OR_TFOOT: {
2634 break;
2636 default: {
2637 errEndWithUnclosedElements(name);
2638 NS_HTML5_BREAK(uncloseloop1);
2642 uncloseloop1_end:;
2644 mode = AFTER_BODY;
2645 NS_HTML5_BREAK(endtagloop);
2647 case HTML: {
2648 if (!isSecondOnStackBody()) {
2649 MOZ_ASSERT(fragment || isTemplateContents());
2650 errStrayEndTag(name);
2651 NS_HTML5_BREAK(endtagloop);
2653 if (MOZ_UNLIKELY(mViewSource)) {
2654 for (int32_t i = 0; i <= currentPtr; i++) {
2655 switch (stack[i]->getGroup()) {
2656 case DD_OR_DT:
2657 case LI:
2658 case P:
2659 case RB_OR_RTC:
2660 case RT_OR_RP:
2661 case TBODY_OR_THEAD_OR_TFOOT:
2662 case TD_OR_TH:
2663 case BODY:
2664 case HTML: {
2665 break;
2667 default: {
2668 errEndWithUnclosedElements(name);
2669 NS_HTML5_BREAK(uncloseloop2);
2673 uncloseloop2_end:;
2675 mode = AFTER_BODY;
2676 continue;
2678 case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
2679 case UL_OR_OL_OR_DL:
2680 case PRE_OR_LISTING:
2681 case FIELDSET:
2682 case BUTTON:
2683 case ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY: {
2684 eltPos = findLastInScope(name);
2685 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2686 errStrayEndTag(name);
2687 } else {
2688 generateImpliedEndTags();
2689 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2690 errUnclosedElements(eltPos, name);
2692 while (currentPtr >= eltPos) {
2693 pop();
2696 NS_HTML5_BREAK(endtagloop);
2698 case FORM: {
2699 if (!isTemplateContents()) {
2700 if (!formPointer) {
2701 errStrayEndTag(name);
2702 NS_HTML5_BREAK(endtagloop);
2704 formPointer = nullptr;
2705 eltPos = findLastInScope(name);
2706 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2707 errStrayEndTag(name);
2708 NS_HTML5_BREAK(endtagloop);
2710 generateImpliedEndTags();
2711 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2712 errUnclosedElements(eltPos, name);
2714 removeFromStack(eltPos);
2715 NS_HTML5_BREAK(endtagloop);
2716 } else {
2717 eltPos = findLastInScope(name);
2718 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2719 errStrayEndTag(name);
2720 NS_HTML5_BREAK(endtagloop);
2722 generateImpliedEndTags();
2723 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2724 errUnclosedElements(eltPos, name);
2726 while (currentPtr >= eltPos) {
2727 pop();
2729 NS_HTML5_BREAK(endtagloop);
2732 case P: {
2733 eltPos = findLastInButtonScope(nsGkAtoms::p);
2734 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2735 errNoElementToCloseButEndTagSeen(nsGkAtoms::p);
2736 if (isInForeign()) {
2737 errHtmlStartTagInForeignContext(name);
2738 while (currentPtr >= 0 &&
2739 stack[currentPtr]->ns != kNameSpaceID_XHTML) {
2740 pop();
2743 appendVoidElementToCurrentMayFoster(
2744 elementName, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
2745 NS_HTML5_BREAK(endtagloop);
2747 generateImpliedEndTagsExceptFor(nsGkAtoms::p);
2748 MOZ_ASSERT(eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK);
2749 if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
2750 errUnclosedElements(eltPos, name);
2752 while (currentPtr >= eltPos) {
2753 pop();
2755 NS_HTML5_BREAK(endtagloop);
2757 case LI: {
2758 eltPos = findLastInListScope(name);
2759 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2760 errNoElementToCloseButEndTagSeen(name);
2761 } else {
2762 generateImpliedEndTagsExceptFor(name);
2763 if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
2764 errUnclosedElements(eltPos, name);
2766 while (currentPtr >= eltPos) {
2767 pop();
2770 NS_HTML5_BREAK(endtagloop);
2772 case DD_OR_DT: {
2773 eltPos = findLastInScope(name);
2774 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2775 errNoElementToCloseButEndTagSeen(name);
2776 } else {
2777 generateImpliedEndTagsExceptFor(name);
2778 if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
2779 errUnclosedElements(eltPos, name);
2781 while (currentPtr >= eltPos) {
2782 pop();
2785 NS_HTML5_BREAK(endtagloop);
2787 case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: {
2788 eltPos = findLastInScopeHn();
2789 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2790 errStrayEndTag(name);
2791 } else {
2792 generateImpliedEndTags();
2793 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2794 errUnclosedElements(eltPos, name);
2796 while (currentPtr >= eltPos) {
2797 pop();
2800 NS_HTML5_BREAK(endtagloop);
2802 case OBJECT:
2803 case MARQUEE_OR_APPLET: {
2804 eltPos = findLastInScope(name);
2805 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2806 errStrayEndTag(name);
2807 } else {
2808 generateImpliedEndTags();
2809 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2810 errUnclosedElements(eltPos, name);
2812 while (currentPtr >= eltPos) {
2813 pop();
2815 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
2817 NS_HTML5_BREAK(endtagloop);
2819 case BR: {
2820 errEndTagBr();
2821 if (isInForeign()) {
2822 errHtmlStartTagInForeignContext(name);
2823 while (currentPtr >= 0 &&
2824 stack[currentPtr]->ns != kNameSpaceID_XHTML) {
2825 pop();
2828 reconstructTheActiveFormattingElements();
2829 appendVoidElementToCurrentMayFoster(
2830 elementName, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
2831 NS_HTML5_BREAK(endtagloop);
2833 case TEMPLATE: {
2834 break;
2836 case AREA_OR_WBR:
2837 case KEYGEN:
2838 #ifdef ENABLE_VOID_MENUITEM
2839 case MENUITEM:
2840 #endif
2841 case PARAM_OR_SOURCE_OR_TRACK:
2842 case EMBED:
2843 case IMG:
2844 case IMAGE:
2845 case INPUT:
2846 case HR:
2847 case IFRAME:
2848 case NOEMBED:
2849 case NOFRAMES:
2850 case SELECT:
2851 case TABLE:
2852 case TEXTAREA: {
2853 errStrayEndTag(name);
2854 NS_HTML5_BREAK(endtagloop);
2856 case NOSCRIPT: {
2857 if (scriptingEnabled) {
2858 errStrayEndTag(name);
2859 NS_HTML5_BREAK(endtagloop);
2861 [[fallthrough]];
2863 case A:
2864 case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
2865 case FONT:
2866 case NOBR: {
2867 if (adoptionAgencyEndTag(name)) {
2868 NS_HTML5_BREAK(endtagloop);
2870 [[fallthrough]];
2872 default: {
2873 if (isCurrent(name)) {
2874 pop();
2875 NS_HTML5_BREAK(endtagloop);
2877 eltPos = currentPtr;
2878 for (;;) {
2879 nsHtml5StackNode* node = stack[eltPos];
2880 if (node->ns == kNameSpaceID_XHTML && node->name == name) {
2881 generateImpliedEndTags();
2882 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2883 errUnclosedElements(eltPos, name);
2885 while (currentPtr >= eltPos) {
2886 pop();
2888 NS_HTML5_BREAK(endtagloop);
2889 } else if (!eltPos || node->isSpecial()) {
2890 errStrayEndTag(name);
2891 NS_HTML5_BREAK(endtagloop);
2893 eltPos--;
2897 [[fallthrough]];
2899 case IN_HEAD: {
2900 switch (group) {
2901 case HEAD: {
2902 pop();
2903 mode = AFTER_HEAD;
2904 NS_HTML5_BREAK(endtagloop);
2906 case BR:
2907 case HTML:
2908 case BODY: {
2909 pop();
2910 mode = AFTER_HEAD;
2911 continue;
2913 case TEMPLATE: {
2914 endTagTemplateInHead();
2915 NS_HTML5_BREAK(endtagloop);
2917 default: {
2918 errStrayEndTag(name);
2919 NS_HTML5_BREAK(endtagloop);
2923 case IN_HEAD_NOSCRIPT: {
2924 switch (group) {
2925 case NOSCRIPT: {
2926 pop();
2927 mode = IN_HEAD;
2928 NS_HTML5_BREAK(endtagloop);
2930 case BR: {
2931 errStrayEndTag(name);
2932 pop();
2933 mode = IN_HEAD;
2934 continue;
2936 default: {
2937 errStrayEndTag(name);
2938 NS_HTML5_BREAK(endtagloop);
2942 case IN_COLUMN_GROUP: {
2943 switch (group) {
2944 case COLGROUP: {
2945 if (!currentPtr ||
2946 stack[currentPtr]->getGroup() == nsHtml5TreeBuilder::TEMPLATE) {
2947 MOZ_ASSERT(fragment || isTemplateContents());
2948 errGarbageInColgroup();
2949 NS_HTML5_BREAK(endtagloop);
2951 pop();
2952 mode = IN_TABLE;
2953 NS_HTML5_BREAK(endtagloop);
2955 case COL: {
2956 errStrayEndTag(name);
2957 NS_HTML5_BREAK(endtagloop);
2959 case TEMPLATE: {
2960 endTagTemplateInHead();
2961 NS_HTML5_BREAK(endtagloop);
2963 default: {
2964 if (!currentPtr ||
2965 stack[currentPtr]->getGroup() == nsHtml5TreeBuilder::TEMPLATE) {
2966 MOZ_ASSERT(fragment || isTemplateContents());
2967 errGarbageInColgroup();
2968 NS_HTML5_BREAK(endtagloop);
2970 pop();
2971 mode = IN_TABLE;
2972 continue;
2976 case IN_SELECT_IN_TABLE: {
2977 switch (group) {
2978 case CAPTION:
2979 case TABLE:
2980 case TBODY_OR_THEAD_OR_TFOOT:
2981 case TR:
2982 case TD_OR_TH: {
2983 errEndTagSeenWithSelectOpen(name);
2984 if (findLastInTableScope(name) !=
2985 nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2986 eltPos = findLastInTableScope(nsGkAtoms::select);
2987 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2988 MOZ_ASSERT(fragment);
2989 NS_HTML5_BREAK(endtagloop);
2991 while (currentPtr >= eltPos) {
2992 pop();
2994 resetTheInsertionMode();
2995 continue;
2996 } else {
2997 NS_HTML5_BREAK(endtagloop);
3000 default:; // fall through
3002 [[fallthrough]];
3004 case IN_SELECT: {
3005 switch (group) {
3006 case OPTION: {
3007 if (isCurrent(nsGkAtoms::option)) {
3008 pop();
3009 NS_HTML5_BREAK(endtagloop);
3010 } else {
3011 errStrayEndTag(name);
3012 NS_HTML5_BREAK(endtagloop);
3015 case OPTGROUP: {
3016 if (isCurrent(nsGkAtoms::option) &&
3017 nsGkAtoms::optgroup == stack[currentPtr - 1]->name) {
3018 pop();
3020 if (isCurrent(nsGkAtoms::optgroup)) {
3021 pop();
3022 } else {
3023 errStrayEndTag(name);
3025 NS_HTML5_BREAK(endtagloop);
3027 case SELECT: {
3028 eltPos = findLastInTableScope(nsGkAtoms::select);
3029 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
3030 MOZ_ASSERT(fragment);
3031 errStrayEndTag(name);
3032 NS_HTML5_BREAK(endtagloop);
3034 while (currentPtr >= eltPos) {
3035 pop();
3037 resetTheInsertionMode();
3038 NS_HTML5_BREAK(endtagloop);
3040 case TEMPLATE: {
3041 endTagTemplateInHead();
3042 NS_HTML5_BREAK(endtagloop);
3044 default: {
3045 errStrayEndTag(name);
3046 NS_HTML5_BREAK(endtagloop);
3050 case AFTER_BODY: {
3051 switch (group) {
3052 case HTML: {
3053 if (fragment) {
3054 errStrayEndTag(name);
3055 NS_HTML5_BREAK(endtagloop);
3056 } else {
3057 mode = AFTER_AFTER_BODY;
3058 NS_HTML5_BREAK(endtagloop);
3061 default: {
3062 errEndTagAfterBody();
3063 mode = framesetOk ? FRAMESET_OK : IN_BODY;
3064 continue;
3068 case IN_FRAMESET: {
3069 switch (group) {
3070 case FRAMESET: {
3071 if (!currentPtr) {
3072 MOZ_ASSERT(fragment);
3073 errStrayEndTag(name);
3074 NS_HTML5_BREAK(endtagloop);
3076 pop();
3077 if ((!fragment) && !isCurrent(nsGkAtoms::frameset)) {
3078 mode = AFTER_FRAMESET;
3080 NS_HTML5_BREAK(endtagloop);
3082 default: {
3083 errStrayEndTag(name);
3084 NS_HTML5_BREAK(endtagloop);
3088 case AFTER_FRAMESET: {
3089 switch (group) {
3090 case HTML: {
3091 mode = AFTER_AFTER_FRAMESET;
3092 NS_HTML5_BREAK(endtagloop);
3094 default: {
3095 errStrayEndTag(name);
3096 NS_HTML5_BREAK(endtagloop);
3100 case INITIAL: {
3101 errEndTagSeenWithoutDoctype();
3102 documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
3103 mode = BEFORE_HTML;
3104 continue;
3106 case BEFORE_HTML: {
3107 switch (group) {
3108 case HEAD:
3109 case BR:
3110 case HTML:
3111 case BODY: {
3112 appendHtmlElementToDocumentAndPush();
3113 mode = BEFORE_HEAD;
3114 continue;
3116 default: {
3117 errStrayEndTag(name);
3118 NS_HTML5_BREAK(endtagloop);
3122 case BEFORE_HEAD: {
3123 switch (group) {
3124 case HEAD:
3125 case BR:
3126 case HTML:
3127 case BODY: {
3128 appendToCurrentNodeAndPushHeadElement(
3129 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
3130 mode = IN_HEAD;
3131 continue;
3133 default: {
3134 errStrayEndTag(name);
3135 NS_HTML5_BREAK(endtagloop);
3139 case AFTER_HEAD: {
3140 switch (group) {
3141 case TEMPLATE: {
3142 endTagTemplateInHead();
3143 NS_HTML5_BREAK(endtagloop);
3145 case HTML:
3146 case BODY:
3147 case BR: {
3148 appendToCurrentNodeAndPushBodyElement();
3149 mode = FRAMESET_OK;
3150 continue;
3152 default: {
3153 errStrayEndTag(name);
3154 NS_HTML5_BREAK(endtagloop);
3158 case AFTER_AFTER_BODY: {
3159 errStrayEndTag(name);
3160 mode = framesetOk ? FRAMESET_OK : IN_BODY;
3161 continue;
3163 case AFTER_AFTER_FRAMESET: {
3164 errStrayEndTag(name);
3165 NS_HTML5_BREAK(endtagloop);
3167 case TEXT: {
3168 pop();
3169 if (originalMode == AFTER_HEAD) {
3170 silentPop();
3172 mode = originalMode;
3173 NS_HTML5_BREAK(endtagloop);
3177 endtagloop_end:;
3180 void nsHtml5TreeBuilder::endTagTemplateInHead() {
3181 int32_t eltPos = findLast(nsGkAtoms::_template);
3182 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
3183 errStrayEndTag(nsGkAtoms::_template);
3184 return;
3186 generateImpliedEndTags();
3187 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(nsGkAtoms::_template)) {
3188 errUnclosedElements(eltPos, nsGkAtoms::_template);
3190 while (currentPtr >= eltPos) {
3191 pop();
3193 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
3194 popTemplateMode();
3195 resetTheInsertionMode();
3198 int32_t
3199 nsHtml5TreeBuilder::findLastInTableScopeOrRootTemplateTbodyTheadTfoot() {
3200 for (int32_t i = currentPtr; i > 0; i--) {
3201 if (stack[i]->getGroup() == nsHtml5TreeBuilder::TBODY_OR_THEAD_OR_TFOOT ||
3202 stack[i]->getGroup() == nsHtml5TreeBuilder::TEMPLATE) {
3203 return i;
3206 return 0;
3209 int32_t nsHtml5TreeBuilder::findLast(nsAtom* name) {
3210 for (int32_t i = currentPtr; i > 0; i--) {
3211 if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) {
3212 return i;
3215 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3218 int32_t nsHtml5TreeBuilder::findLastInTableScope(nsAtom* name) {
3219 for (int32_t i = currentPtr; i > 0; i--) {
3220 if (stack[i]->ns == kNameSpaceID_XHTML) {
3221 if (stack[i]->name == name) {
3222 return i;
3223 } else if (stack[i]->name == nsGkAtoms::table ||
3224 stack[i]->name == nsGkAtoms::_template) {
3225 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3229 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3232 int32_t nsHtml5TreeBuilder::findLastInButtonScope(nsAtom* name) {
3233 for (int32_t i = currentPtr; i > 0; i--) {
3234 if (stack[i]->ns == kNameSpaceID_XHTML) {
3235 if (stack[i]->name == name) {
3236 return i;
3237 } else if (stack[i]->name == nsGkAtoms::button) {
3238 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3241 if (stack[i]->isScoping()) {
3242 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3245 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3248 int32_t nsHtml5TreeBuilder::findLastInScope(nsAtom* name) {
3249 for (int32_t i = currentPtr; i > 0; i--) {
3250 if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) {
3251 return i;
3252 } else if (stack[i]->isScoping()) {
3253 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3256 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3259 int32_t nsHtml5TreeBuilder::findLastInListScope(nsAtom* name) {
3260 for (int32_t i = currentPtr; i > 0; i--) {
3261 if (stack[i]->ns == kNameSpaceID_XHTML) {
3262 if (stack[i]->name == name) {
3263 return i;
3264 } else if (stack[i]->name == nsGkAtoms::ul ||
3265 stack[i]->name == nsGkAtoms::ol) {
3266 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3269 if (stack[i]->isScoping()) {
3270 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3273 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3276 int32_t nsHtml5TreeBuilder::findLastInScopeHn() {
3277 for (int32_t i = currentPtr; i > 0; i--) {
3278 if (stack[i]->getGroup() ==
3279 nsHtml5TreeBuilder::H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
3280 return i;
3281 } else if (stack[i]->isScoping()) {
3282 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3285 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3288 void nsHtml5TreeBuilder::generateImpliedEndTagsExceptFor(nsAtom* name) {
3289 for (;;) {
3290 nsHtml5StackNode* node = stack[currentPtr];
3291 switch (node->getGroup()) {
3292 case P:
3293 case LI:
3294 case DD_OR_DT:
3295 case OPTION:
3296 case OPTGROUP:
3297 case RB_OR_RTC:
3298 case RT_OR_RP: {
3299 if (node->ns == kNameSpaceID_XHTML && node->name == name) {
3300 return;
3302 pop();
3303 continue;
3305 default: {
3306 return;
3312 void nsHtml5TreeBuilder::generateImpliedEndTags() {
3313 for (;;) {
3314 switch (stack[currentPtr]->getGroup()) {
3315 case P:
3316 case LI:
3317 case DD_OR_DT:
3318 case OPTION:
3319 case OPTGROUP:
3320 case RB_OR_RTC:
3321 case RT_OR_RP: {
3322 pop();
3323 continue;
3325 default: {
3326 return;
3332 bool nsHtml5TreeBuilder::isSecondOnStackBody() {
3333 return currentPtr >= 1 && stack[1]->getGroup() == nsHtml5TreeBuilder::BODY;
3336 void nsHtml5TreeBuilder::documentModeInternal(nsHtml5DocumentMode m,
3337 nsHtml5String publicIdentifier,
3338 nsHtml5String systemIdentifier) {
3339 if (isSrcdocDocument) {
3340 quirks = false;
3341 this->documentMode(STANDARDS_MODE);
3342 return;
3344 quirks = (m == QUIRKS_MODE);
3345 this->documentMode(m);
3348 bool nsHtml5TreeBuilder::isAlmostStandards(nsHtml5String publicIdentifier,
3349 nsHtml5String systemIdentifier) {
3350 if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3351 "-//w3c//dtd xhtml 1.0 transitional//", publicIdentifier)) {
3352 return true;
3354 if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3355 "-//w3c//dtd xhtml 1.0 frameset//", publicIdentifier)) {
3356 return true;
3358 if (systemIdentifier) {
3359 if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3360 "-//w3c//dtd html 4.01 transitional//", publicIdentifier)) {
3361 return true;
3363 if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3364 "-//w3c//dtd html 4.01 frameset//", publicIdentifier)) {
3365 return true;
3368 return false;
3371 bool nsHtml5TreeBuilder::isQuirky(nsAtom* name, nsHtml5String publicIdentifier,
3372 nsHtml5String systemIdentifier,
3373 bool forceQuirks) {
3374 if (forceQuirks) {
3375 return true;
3377 if (name != nsGkAtoms::html) {
3378 return true;
3380 if (publicIdentifier) {
3381 for (int32_t i = 0; i < nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS.length; i++) {
3382 if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3383 nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS[i], publicIdentifier)) {
3384 return true;
3387 if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
3388 "-//w3o//dtd w3 html strict 3.0//en//", publicIdentifier) ||
3389 nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
3390 "-/w3c/dtd html 4.0 transitional/en", publicIdentifier) ||
3391 nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
3392 "html", publicIdentifier)) {
3393 return true;
3396 if (!systemIdentifier) {
3397 if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3398 "-//w3c//dtd html 4.01 transitional//", publicIdentifier)) {
3399 return true;
3400 } else if (nsHtml5Portability::
3401 lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3402 "-//w3c//dtd html 4.01 frameset//", publicIdentifier)) {
3403 return true;
3405 } else if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
3406 "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd",
3407 systemIdentifier)) {
3408 return true;
3410 return false;
3413 void nsHtml5TreeBuilder::closeTheCell(int32_t eltPos) {
3414 generateImpliedEndTags();
3415 if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
3416 errUnclosedElementsCell(eltPos);
3418 while (currentPtr >= eltPos) {
3419 pop();
3421 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
3422 mode = IN_ROW;
3423 return;
3426 int32_t nsHtml5TreeBuilder::findLastInTableScopeTdTh() {
3427 for (int32_t i = currentPtr; i > 0; i--) {
3428 nsAtom* name = stack[i]->name;
3429 if (stack[i]->ns == kNameSpaceID_XHTML) {
3430 if (nsGkAtoms::td == name || nsGkAtoms::th == name) {
3431 return i;
3432 } else if (name == nsGkAtoms::table || name == nsGkAtoms::_template) {
3433 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3437 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3440 void nsHtml5TreeBuilder::clearStackBackTo(int32_t eltPos) {
3441 int32_t eltGroup = stack[eltPos]->getGroup();
3442 while (currentPtr > eltPos) {
3443 if (stack[currentPtr]->ns == kNameSpaceID_XHTML &&
3444 stack[currentPtr]->getGroup() == TEMPLATE &&
3445 (eltGroup == TABLE || eltGroup == TBODY_OR_THEAD_OR_TFOOT ||
3446 eltGroup == TR || !eltPos)) {
3447 return;
3449 pop();
3453 void nsHtml5TreeBuilder::resetTheInsertionMode() {
3454 nsHtml5StackNode* node;
3455 nsAtom* name;
3456 int32_t ns;
3457 for (int32_t i = currentPtr; i >= 0; i--) {
3458 node = stack[i];
3459 name = node->name;
3460 ns = node->ns;
3461 if (!i) {
3462 if (!(contextNamespace == kNameSpaceID_XHTML &&
3463 (contextName == nsGkAtoms::td || contextName == nsGkAtoms::th))) {
3464 if (fragment) {
3465 name = contextName;
3466 ns = contextNamespace;
3468 } else {
3469 mode = framesetOk ? FRAMESET_OK : IN_BODY;
3470 return;
3473 if (nsGkAtoms::select == name) {
3474 int32_t ancestorIndex = i;
3475 while (ancestorIndex > 0) {
3476 nsHtml5StackNode* ancestor = stack[ancestorIndex--];
3477 if (kNameSpaceID_XHTML == ancestor->ns) {
3478 if (nsGkAtoms::_template == ancestor->name) {
3479 break;
3481 if (nsGkAtoms::table == ancestor->name) {
3482 mode = IN_SELECT_IN_TABLE;
3483 return;
3487 mode = IN_SELECT;
3488 return;
3489 } else if (nsGkAtoms::td == name || nsGkAtoms::th == name) {
3490 mode = IN_CELL;
3491 return;
3492 } else if (nsGkAtoms::tr == name) {
3493 mode = IN_ROW;
3494 return;
3495 } else if (nsGkAtoms::tbody == name || nsGkAtoms::thead == name ||
3496 nsGkAtoms::tfoot == name) {
3497 mode = IN_TABLE_BODY;
3498 return;
3499 } else if (nsGkAtoms::caption == name) {
3500 mode = IN_CAPTION;
3501 return;
3502 } else if (nsGkAtoms::colgroup == name) {
3503 mode = IN_COLUMN_GROUP;
3504 return;
3505 } else if (nsGkAtoms::table == name) {
3506 mode = IN_TABLE;
3507 return;
3508 } else if (kNameSpaceID_XHTML != ns) {
3509 mode = framesetOk ? FRAMESET_OK : IN_BODY;
3510 return;
3511 } else if (nsGkAtoms::_template == name) {
3512 MOZ_ASSERT(templateModePtr >= 0);
3513 mode = templateModeStack[templateModePtr];
3514 return;
3515 } else if (nsGkAtoms::head == name) {
3516 if (name == contextName) {
3517 mode = framesetOk ? FRAMESET_OK : IN_BODY;
3518 } else {
3519 mode = IN_HEAD;
3521 return;
3522 } else if (nsGkAtoms::body == name) {
3523 mode = framesetOk ? FRAMESET_OK : IN_BODY;
3524 return;
3525 } else if (nsGkAtoms::frameset == name) {
3526 mode = IN_FRAMESET;
3527 return;
3528 } else if (nsGkAtoms::html == name) {
3529 if (!headPointer) {
3530 mode = BEFORE_HEAD;
3531 } else {
3532 mode = AFTER_HEAD;
3534 return;
3535 } else if (!i) {
3536 mode = framesetOk ? FRAMESET_OK : IN_BODY;
3537 return;
3542 void nsHtml5TreeBuilder::implicitlyCloseP() {
3543 int32_t eltPos = findLastInButtonScope(nsGkAtoms::p);
3544 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
3545 return;
3547 generateImpliedEndTagsExceptFor(nsGkAtoms::p);
3548 if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
3549 errUnclosedElementsImplied(eltPos, nsGkAtoms::p);
3551 while (currentPtr >= eltPos) {
3552 pop();
3556 bool nsHtml5TreeBuilder::debugOnlyClearLastStackSlot() {
3557 stack[currentPtr] = nullptr;
3558 return true;
3561 bool nsHtml5TreeBuilder::debugOnlyClearLastListSlot() {
3562 listOfActiveFormattingElements[listPtr] = nullptr;
3563 return true;
3566 void nsHtml5TreeBuilder::pushTemplateMode(int32_t mode) {
3567 templateModePtr++;
3568 if (templateModePtr == templateModeStack.length) {
3569 jArray<int32_t, int32_t> newStack =
3570 jArray<int32_t, int32_t>::newJArray(templateModeStack.length + 64);
3571 nsHtml5ArrayCopy::arraycopy(templateModeStack, newStack,
3572 templateModeStack.length);
3573 templateModeStack = newStack;
3575 templateModeStack[templateModePtr] = mode;
3578 void nsHtml5TreeBuilder::push(nsHtml5StackNode* node) {
3579 currentPtr++;
3580 if (currentPtr == stack.length) {
3581 jArray<nsHtml5StackNode*, int32_t> newStack =
3582 jArray<nsHtml5StackNode*, int32_t>::newJArray(stack.length + 64);
3583 nsHtml5ArrayCopy::arraycopy(stack, newStack, stack.length);
3584 stack = newStack;
3586 stack[currentPtr] = node;
3587 elementPushed(node->ns, node->popName, node->node);
3590 void nsHtml5TreeBuilder::silentPush(nsHtml5StackNode* node) {
3591 currentPtr++;
3592 if (currentPtr == stack.length) {
3593 jArray<nsHtml5StackNode*, int32_t> newStack =
3594 jArray<nsHtml5StackNode*, int32_t>::newJArray(stack.length + 64);
3595 nsHtml5ArrayCopy::arraycopy(stack, newStack, stack.length);
3596 stack = newStack;
3598 stack[currentPtr] = node;
3601 void nsHtml5TreeBuilder::append(nsHtml5StackNode* node) {
3602 listPtr++;
3603 if (listPtr == listOfActiveFormattingElements.length) {
3604 jArray<nsHtml5StackNode*, int32_t> newList =
3605 jArray<nsHtml5StackNode*, int32_t>::newJArray(
3606 listOfActiveFormattingElements.length + 64);
3607 nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, newList,
3608 listOfActiveFormattingElements.length);
3609 listOfActiveFormattingElements = newList;
3611 listOfActiveFormattingElements[listPtr] = node;
3614 void nsHtml5TreeBuilder::
3615 clearTheListOfActiveFormattingElementsUpToTheLastMarker() {
3616 while (listPtr > -1) {
3617 if (!listOfActiveFormattingElements[listPtr]) {
3618 --listPtr;
3619 return;
3621 listOfActiveFormattingElements[listPtr]->release(this);
3622 --listPtr;
3626 void nsHtml5TreeBuilder::removeFromStack(int32_t pos) {
3627 if (currentPtr == pos) {
3628 pop();
3629 } else {
3630 stack[pos]->release(this);
3631 nsHtml5ArrayCopy::arraycopy(stack, pos + 1, pos, currentPtr - pos);
3632 MOZ_ASSERT(debugOnlyClearLastStackSlot());
3633 currentPtr--;
3637 void nsHtml5TreeBuilder::removeFromStack(nsHtml5StackNode* node) {
3638 if (stack[currentPtr] == node) {
3639 pop();
3640 } else {
3641 int32_t pos = currentPtr - 1;
3642 while (pos >= 0 && stack[pos] != node) {
3643 pos--;
3645 if (pos == -1) {
3646 return;
3649 node->release(this);
3650 nsHtml5ArrayCopy::arraycopy(stack, pos + 1, pos, currentPtr - pos);
3651 currentPtr--;
3655 void nsHtml5TreeBuilder::removeFromListOfActiveFormattingElements(int32_t pos) {
3656 MOZ_ASSERT(!!listOfActiveFormattingElements[pos]);
3657 listOfActiveFormattingElements[pos]->release(this);
3658 if (pos == listPtr) {
3659 MOZ_ASSERT(debugOnlyClearLastListSlot());
3660 listPtr--;
3661 return;
3663 MOZ_ASSERT(pos < listPtr);
3664 nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, pos + 1, pos,
3665 listPtr - pos);
3666 MOZ_ASSERT(debugOnlyClearLastListSlot());
3667 listPtr--;
3670 bool nsHtml5TreeBuilder::adoptionAgencyEndTag(nsAtom* name) {
3671 if (stack[currentPtr]->ns == kNameSpaceID_XHTML &&
3672 stack[currentPtr]->name == name &&
3673 findInListOfActiveFormattingElements(stack[currentPtr]) == -1) {
3674 pop();
3675 return true;
3677 for (int32_t i = 0; i < 8; ++i) {
3678 int32_t formattingEltListPos = listPtr;
3679 while (formattingEltListPos > -1) {
3680 nsHtml5StackNode* listNode =
3681 listOfActiveFormattingElements[formattingEltListPos];
3682 if (!listNode) {
3683 formattingEltListPos = -1;
3684 break;
3685 } else if (listNode->name == name) {
3686 break;
3688 formattingEltListPos--;
3690 if (formattingEltListPos == -1) {
3691 return false;
3693 nsHtml5StackNode* formattingElt =
3694 listOfActiveFormattingElements[formattingEltListPos];
3695 int32_t formattingEltStackPos = currentPtr;
3696 bool inScope = true;
3697 while (formattingEltStackPos > -1) {
3698 nsHtml5StackNode* node = stack[formattingEltStackPos];
3699 if (node == formattingElt) {
3700 break;
3701 } else if (node->isScoping()) {
3702 inScope = false;
3704 formattingEltStackPos--;
3706 if (formattingEltStackPos == -1) {
3707 errNoElementToCloseButEndTagSeen(name);
3708 removeFromListOfActiveFormattingElements(formattingEltListPos);
3709 return true;
3711 if (!inScope) {
3712 errNoElementToCloseButEndTagSeen(name);
3713 return true;
3715 if (formattingEltStackPos != currentPtr) {
3716 errEndTagViolatesNestingRules(name);
3718 int32_t furthestBlockPos = formattingEltStackPos + 1;
3719 while (furthestBlockPos <= currentPtr) {
3720 nsHtml5StackNode* node = stack[furthestBlockPos];
3721 MOZ_ASSERT(furthestBlockPos > 0,
3722 "How is formattingEltStackPos + 1 not > 0?");
3723 if (node->isSpecial()) {
3724 break;
3726 furthestBlockPos++;
3728 if (furthestBlockPos > currentPtr) {
3729 while (currentPtr >= formattingEltStackPos) {
3730 pop();
3732 removeFromListOfActiveFormattingElements(formattingEltListPos);
3733 return true;
3735 nsHtml5StackNode* commonAncestor = stack[formattingEltStackPos - 1];
3736 nsIContentHandle* insertionCommonAncestor =
3737 nodeFromStackWithBlinkCompat(formattingEltStackPos - 1);
3738 nsHtml5StackNode* furthestBlock = stack[furthestBlockPos];
3739 int32_t bookmark = formattingEltListPos;
3740 int32_t nodePos = furthestBlockPos;
3741 nsHtml5StackNode* lastNode = furthestBlock;
3742 int32_t j = 0;
3743 for (;;) {
3744 ++j;
3745 nodePos--;
3746 if (nodePos == formattingEltStackPos) {
3747 break;
3749 nsHtml5StackNode* node = stack[nodePos];
3750 int32_t nodeListPos = findInListOfActiveFormattingElements(node);
3751 if (j > 3 && nodeListPos != -1) {
3752 removeFromListOfActiveFormattingElements(nodeListPos);
3753 if (nodeListPos <= formattingEltListPos) {
3754 formattingEltListPos--;
3756 if (nodeListPos <= bookmark) {
3757 bookmark--;
3759 nodeListPos = -1;
3761 if (nodeListPos == -1) {
3762 MOZ_ASSERT(formattingEltStackPos < nodePos);
3763 MOZ_ASSERT(bookmark < nodePos);
3764 MOZ_ASSERT(furthestBlockPos > nodePos);
3765 removeFromStack(nodePos);
3766 furthestBlockPos--;
3767 continue;
3769 if (nodePos == furthestBlockPos) {
3770 bookmark = nodeListPos + 1;
3772 MOZ_ASSERT(node == listOfActiveFormattingElements[nodeListPos]);
3773 MOZ_ASSERT(node == stack[nodePos]);
3774 nsIContentHandle* clone = createElement(
3775 kNameSpaceID_XHTML, node->name, node->attributes->cloneAttributes(),
3776 insertionCommonAncestor, htmlCreator(node->getHtmlCreator()));
3777 nsHtml5StackNode* newNode = createStackNode(
3778 node->getFlags(), node->ns, node->name, clone, node->popName,
3779 node->attributes, node->getHtmlCreator());
3780 node->dropAttributes();
3781 stack[nodePos] = newNode;
3782 newNode->retain();
3783 listOfActiveFormattingElements[nodeListPos] = newNode;
3784 node->release(this);
3785 node->release(this);
3786 node = newNode;
3787 detachFromParent(lastNode->node);
3788 appendElement(lastNode->node, nodeFromStackWithBlinkCompat(nodePos));
3789 lastNode = node;
3791 if (commonAncestor->isFosterParenting()) {
3792 detachFromParent(lastNode->node);
3793 insertIntoFosterParent(lastNode->node);
3794 } else {
3795 detachFromParent(lastNode->node);
3796 appendElement(lastNode->node, insertionCommonAncestor);
3798 nsIContentHandle* clone = createElement(
3799 kNameSpaceID_XHTML, formattingElt->name,
3800 formattingElt->attributes->cloneAttributes(), furthestBlock->node,
3801 htmlCreator(formattingElt->getHtmlCreator()));
3802 nsHtml5StackNode* formattingClone = createStackNode(
3803 formattingElt->getFlags(), formattingElt->ns, formattingElt->name,
3804 clone, formattingElt->popName, formattingElt->attributes,
3805 formattingElt->getHtmlCreator());
3806 formattingElt->dropAttributes();
3807 appendChildrenToNewParent(furthestBlock->node, clone);
3808 appendElement(clone, furthestBlock->node);
3809 removeFromListOfActiveFormattingElements(formattingEltListPos);
3810 insertIntoListOfActiveFormattingElements(formattingClone, bookmark);
3811 MOZ_ASSERT(formattingEltStackPos < furthestBlockPos);
3812 removeFromStack(formattingEltStackPos);
3813 insertIntoStack(formattingClone, furthestBlockPos);
3815 return true;
3818 void nsHtml5TreeBuilder::insertIntoStack(nsHtml5StackNode* node,
3819 int32_t position) {
3820 MOZ_ASSERT(currentPtr + 1 < stack.length);
3821 MOZ_ASSERT(position <= currentPtr + 1);
3822 if (position == currentPtr + 1) {
3823 push(node);
3824 } else {
3825 nsHtml5ArrayCopy::arraycopy(stack, position, position + 1,
3826 (currentPtr - position) + 1);
3827 currentPtr++;
3828 stack[position] = node;
3832 void nsHtml5TreeBuilder::insertIntoListOfActiveFormattingElements(
3833 nsHtml5StackNode* formattingClone, int32_t bookmark) {
3834 formattingClone->retain();
3835 MOZ_ASSERT(listPtr + 1 < listOfActiveFormattingElements.length);
3836 if (bookmark <= listPtr) {
3837 nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, bookmark,
3838 bookmark + 1, (listPtr - bookmark) + 1);
3840 listPtr++;
3841 listOfActiveFormattingElements[bookmark] = formattingClone;
3844 int32_t nsHtml5TreeBuilder::findInListOfActiveFormattingElements(
3845 nsHtml5StackNode* node) {
3846 for (int32_t i = listPtr; i >= 0; i--) {
3847 if (node == listOfActiveFormattingElements[i]) {
3848 return i;
3851 return -1;
3854 int32_t nsHtml5TreeBuilder::
3855 findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(
3856 nsAtom* name) {
3857 for (int32_t i = listPtr; i >= 0; i--) {
3858 nsHtml5StackNode* node = listOfActiveFormattingElements[i];
3859 if (!node) {
3860 return -1;
3861 } else if (node->name == name) {
3862 return i;
3865 return -1;
3868 void nsHtml5TreeBuilder::maybeForgetEarlierDuplicateFormattingElement(
3869 nsAtom* name, nsHtml5HtmlAttributes* attributes) {
3870 int32_t candidate = -1;
3871 int32_t count = 0;
3872 for (int32_t i = listPtr; i >= 0; i--) {
3873 nsHtml5StackNode* node = listOfActiveFormattingElements[i];
3874 if (!node) {
3875 break;
3877 if (node->name == name && node->attributes->equalsAnother(attributes)) {
3878 candidate = i;
3879 ++count;
3882 if (count >= 3) {
3883 removeFromListOfActiveFormattingElements(candidate);
3887 int32_t nsHtml5TreeBuilder::findLastOrRoot(nsAtom* name) {
3888 for (int32_t i = currentPtr; i > 0; i--) {
3889 if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) {
3890 return i;
3893 return 0;
3896 int32_t nsHtml5TreeBuilder::findLastOrRoot(int32_t group) {
3897 for (int32_t i = currentPtr; i > 0; i--) {
3898 if (stack[i]->getGroup() == group) {
3899 return i;
3902 return 0;
3905 bool nsHtml5TreeBuilder::addAttributesToBody(
3906 nsHtml5HtmlAttributes* attributes) {
3907 if (currentPtr >= 1) {
3908 nsHtml5StackNode* body = stack[1];
3909 if (body->getGroup() == nsHtml5TreeBuilder::BODY) {
3910 addAttributesToElement(body->node, attributes);
3911 return true;
3914 return false;
3917 void nsHtml5TreeBuilder::addAttributesToHtml(
3918 nsHtml5HtmlAttributes* attributes) {
3919 addAttributesToElement(stack[0]->node, attributes);
3922 void nsHtml5TreeBuilder::pushHeadPointerOntoStack() {
3923 MOZ_ASSERT(!!headPointer);
3924 MOZ_ASSERT(mode == AFTER_HEAD);
3926 silentPush(createStackNode(nsHtml5ElementName::ELT_HEAD, headPointer));
3929 void nsHtml5TreeBuilder::reconstructTheActiveFormattingElements() {
3930 if (listPtr == -1) {
3931 return;
3933 nsHtml5StackNode* mostRecent = listOfActiveFormattingElements[listPtr];
3934 if (!mostRecent || isInStack(mostRecent)) {
3935 return;
3937 int32_t entryPos = listPtr;
3938 for (;;) {
3939 entryPos--;
3940 if (entryPos == -1) {
3941 break;
3943 if (!listOfActiveFormattingElements[entryPos]) {
3944 break;
3946 if (isInStack(listOfActiveFormattingElements[entryPos])) {
3947 break;
3950 while (entryPos < listPtr) {
3951 entryPos++;
3952 nsHtml5StackNode* entry = listOfActiveFormattingElements[entryPos];
3953 nsHtml5StackNode* current = stack[currentPtr];
3954 nsIContentHandle* clone;
3955 if (current->isFosterParenting()) {
3956 clone = createAndInsertFosterParentedElement(
3957 kNameSpaceID_XHTML, entry->name, entry->attributes->cloneAttributes(),
3958 htmlCreator(entry->getHtmlCreator()));
3959 } else {
3960 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
3961 clone = createElement(kNameSpaceID_XHTML, entry->name,
3962 entry->attributes->cloneAttributes(), currentNode,
3963 htmlCreator(entry->getHtmlCreator()));
3964 appendElement(clone, currentNode);
3966 nsHtml5StackNode* entryClone = createStackNode(
3967 entry->getFlags(), entry->ns, entry->name, clone, entry->popName,
3968 entry->attributes, entry->getHtmlCreator());
3969 entry->dropAttributes();
3970 push(entryClone);
3971 listOfActiveFormattingElements[entryPos] = entryClone;
3972 entry->release(this);
3973 entryClone->retain();
3977 void nsHtml5TreeBuilder::notifyUnusedStackNode(int32_t idxInStackNodes) {
3978 if (idxInStackNodes < stackNodesIdx) {
3979 stackNodesIdx = idxInStackNodes;
3983 nsHtml5StackNode* nsHtml5TreeBuilder::getUnusedStackNode() {
3984 while (stackNodesIdx < numStackNodes) {
3985 if (stackNodes[stackNodesIdx]->isUnused()) {
3986 return stackNodes[stackNodesIdx++];
3988 stackNodesIdx++;
3990 if (stackNodesIdx < stackNodes.length) {
3991 stackNodes[stackNodesIdx] = new nsHtml5StackNode(stackNodesIdx);
3992 numStackNodes++;
3993 return stackNodes[stackNodesIdx++];
3995 jArray<nsHtml5StackNode*, int32_t> newStack =
3996 jArray<nsHtml5StackNode*, int32_t>::newJArray(stackNodes.length + 64);
3997 nsHtml5ArrayCopy::arraycopy(stackNodes, newStack, stackNodes.length);
3998 stackNodes = newStack;
3999 stackNodes[stackNodesIdx] = new nsHtml5StackNode(stackNodesIdx);
4000 numStackNodes++;
4001 return stackNodes[stackNodesIdx++];
4004 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4005 int32_t flags, int32_t ns, nsAtom* name, nsIContentHandle* node,
4006 nsAtom* popName, nsHtml5HtmlAttributes* attributes,
4007 mozilla::dom::HTMLContentCreatorFunction htmlCreator) {
4008 nsHtml5StackNode* instance = getUnusedStackNode();
4009 instance->setValues(flags, ns, name, node, popName, attributes, htmlCreator);
4010 return instance;
4013 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4014 nsHtml5ElementName* elementName, nsIContentHandle* node) {
4015 nsHtml5StackNode* instance = getUnusedStackNode();
4016 instance->setValues(elementName, node);
4017 return instance;
4020 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4021 nsHtml5ElementName* elementName, nsIContentHandle* node,
4022 nsHtml5HtmlAttributes* attributes) {
4023 nsHtml5StackNode* instance = getUnusedStackNode();
4024 instance->setValues(elementName, node, attributes);
4025 return instance;
4028 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4029 nsHtml5ElementName* elementName, nsIContentHandle* node, nsAtom* popName) {
4030 nsHtml5StackNode* instance = getUnusedStackNode();
4031 instance->setValues(elementName, node, popName);
4032 return instance;
4035 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4036 nsHtml5ElementName* elementName, nsAtom* popName, nsIContentHandle* node) {
4037 nsHtml5StackNode* instance = getUnusedStackNode();
4038 instance->setValues(elementName, popName, node);
4039 return instance;
4042 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4043 nsHtml5ElementName* elementName, nsIContentHandle* node, nsAtom* popName,
4044 bool markAsIntegrationPoint) {
4045 nsHtml5StackNode* instance = getUnusedStackNode();
4046 instance->setValues(elementName, node, popName, markAsIntegrationPoint);
4047 return instance;
4050 void nsHtml5TreeBuilder::insertIntoFosterParent(nsIContentHandle* child) {
4051 int32_t tablePos = findLastOrRoot(nsHtml5TreeBuilder::TABLE);
4052 int32_t templatePos = findLastOrRoot(nsHtml5TreeBuilder::TEMPLATE);
4053 if (templatePos >= tablePos) {
4054 appendElement(child, stack[templatePos]->node);
4055 return;
4057 nsHtml5StackNode* node = stack[tablePos];
4058 insertFosterParentedChild(child, node->node, stack[tablePos - 1]->node);
4061 nsIContentHandle* nsHtml5TreeBuilder::createAndInsertFosterParentedElement(
4062 int32_t ns, nsAtom* name, nsHtml5HtmlAttributes* attributes,
4063 nsHtml5ContentCreatorFunction creator) {
4064 return createAndInsertFosterParentedElement(ns, name, attributes, nullptr,
4065 creator);
4068 nsIContentHandle* nsHtml5TreeBuilder::createAndInsertFosterParentedElement(
4069 int32_t ns, nsAtom* name, nsHtml5HtmlAttributes* attributes,
4070 nsIContentHandle* form, nsHtml5ContentCreatorFunction creator) {
4071 int32_t tablePos = findLastOrRoot(nsHtml5TreeBuilder::TABLE);
4072 int32_t templatePos = findLastOrRoot(nsHtml5TreeBuilder::TEMPLATE);
4073 if (templatePos >= tablePos) {
4074 nsIContentHandle* child = createElement(ns, name, attributes, form,
4075 stack[templatePos]->node, creator);
4076 appendElement(child, stack[templatePos]->node);
4077 return child;
4079 nsHtml5StackNode* node = stack[tablePos];
4080 return createAndInsertFosterParentedElement(
4081 ns, name, attributes, form, node->node, stack[tablePos - 1]->node,
4082 creator);
4085 bool nsHtml5TreeBuilder::isInStack(nsHtml5StackNode* node) {
4086 for (int32_t i = currentPtr; i >= 0; i--) {
4087 if (stack[i] == node) {
4088 return true;
4091 return false;
4094 void nsHtml5TreeBuilder::popTemplateMode() { templateModePtr--; }
4096 void nsHtml5TreeBuilder::pop() {
4097 nsHtml5StackNode* node = stack[currentPtr];
4098 MOZ_ASSERT(debugOnlyClearLastStackSlot());
4099 currentPtr--;
4100 elementPopped(node->ns, node->popName, node->node);
4101 node->release(this);
4104 void nsHtml5TreeBuilder::popForeign(int32_t origPos, int32_t eltPos) {
4105 nsHtml5StackNode* node = stack[currentPtr];
4106 if (origPos != currentPtr || eltPos != currentPtr) {
4107 markMalformedIfScript(node->node);
4109 MOZ_ASSERT(debugOnlyClearLastStackSlot());
4110 currentPtr--;
4111 elementPopped(node->ns, node->popName, node->node);
4112 node->release(this);
4115 void nsHtml5TreeBuilder::silentPop() {
4116 nsHtml5StackNode* node = stack[currentPtr];
4117 MOZ_ASSERT(debugOnlyClearLastStackSlot());
4118 currentPtr--;
4119 node->release(this);
4122 void nsHtml5TreeBuilder::popOnEof() {
4123 nsHtml5StackNode* node = stack[currentPtr];
4124 MOZ_ASSERT(debugOnlyClearLastStackSlot());
4125 currentPtr--;
4126 markMalformedIfScript(node->node);
4127 elementPopped(node->ns, node->popName, node->node);
4128 node->release(this);
4131 void nsHtml5TreeBuilder::appendHtmlElementToDocumentAndPush(
4132 nsHtml5HtmlAttributes* attributes) {
4133 nsIContentHandle* elt = createHtmlElementSetAsRoot(attributes);
4134 nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_HTML, elt);
4135 push(node);
4138 void nsHtml5TreeBuilder::appendHtmlElementToDocumentAndPush() {
4139 appendHtmlElementToDocumentAndPush(tokenizer->emptyAttributes());
4142 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushHeadElement(
4143 nsHtml5HtmlAttributes* attributes) {
4144 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4145 nsIContentHandle* elt =
4146 createElement(kNameSpaceID_XHTML, nsGkAtoms::head, attributes,
4147 currentNode, htmlCreator(NS_NewHTMLSharedElement));
4148 appendElement(elt, currentNode);
4149 headPointer = elt;
4150 nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_HEAD, elt);
4151 push(node);
4154 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushBodyElement(
4155 nsHtml5HtmlAttributes* attributes) {
4156 appendToCurrentNodeAndPushElement(nsHtml5ElementName::ELT_BODY, attributes);
4159 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushBodyElement() {
4160 appendToCurrentNodeAndPushBodyElement(tokenizer->emptyAttributes());
4163 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormElementMayFoster(
4164 nsHtml5HtmlAttributes* attributes) {
4165 nsIContentHandle* elt;
4166 nsHtml5StackNode* current = stack[currentPtr];
4167 if (current->isFosterParenting()) {
4168 elt = createAndInsertFosterParentedElement(
4169 kNameSpaceID_XHTML, nsGkAtoms::form, attributes,
4170 htmlCreator(NS_NewHTMLFormElement));
4171 } else {
4172 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4173 elt = createElement(kNameSpaceID_XHTML, nsGkAtoms::form, attributes,
4174 currentNode, htmlCreator(NS_NewHTMLFormElement));
4175 appendElement(elt, currentNode);
4177 if (!isTemplateContents()) {
4178 formPointer = elt;
4180 nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_FORM, elt);
4181 push(node);
4184 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormattingElementMayFoster(
4185 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4186 nsHtml5HtmlAttributes* clone = attributes->cloneAttributes();
4187 nsIContentHandle* elt;
4188 nsHtml5StackNode* current = stack[currentPtr];
4189 if (current->isFosterParenting()) {
4190 elt = createAndInsertFosterParentedElement(
4191 kNameSpaceID_XHTML, elementName->getName(), attributes,
4192 htmlCreator(elementName->getHtmlCreator()));
4193 } else {
4194 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4195 elt =
4196 createElement(kNameSpaceID_XHTML, elementName->getName(), attributes,
4197 currentNode, htmlCreator(elementName->getHtmlCreator()));
4198 appendElement(elt, currentNode);
4200 nsHtml5StackNode* node = createStackNode(elementName, elt, clone);
4201 push(node);
4202 append(node);
4203 node->retain();
4206 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElement(
4207 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4208 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4209 nsIContentHandle* elt =
4210 createElement(kNameSpaceID_XHTML, elementName->getName(), attributes,
4211 currentNode, htmlCreator(elementName->getHtmlCreator()));
4212 appendElement(elt, currentNode);
4213 if (nsHtml5ElementName::ELT_TEMPLATE == elementName) {
4214 elt = getDocumentFragmentForTemplate(elt);
4216 nsHtml5StackNode* node = createStackNode(elementName, elt);
4217 push(node);
4220 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(
4221 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4222 nsAtom* popName = elementName->getName();
4223 nsIContentHandle* elt;
4224 nsHtml5StackNode* current = stack[currentPtr];
4225 if (current->isFosterParenting()) {
4226 elt = createAndInsertFosterParentedElement(
4227 kNameSpaceID_XHTML, popName, attributes,
4228 htmlCreator(elementName->getHtmlCreator()));
4229 } else {
4230 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4231 elt = createElement(kNameSpaceID_XHTML, popName, attributes, currentNode,
4232 htmlCreator(elementName->getHtmlCreator()));
4233 appendElement(elt, currentNode);
4235 nsHtml5StackNode* node = createStackNode(elementName, elt, popName);
4236 push(node);
4239 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterMathML(
4240 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4241 nsAtom* popName = elementName->getName();
4242 bool markAsHtmlIntegrationPoint = false;
4243 if (nsHtml5ElementName::ELT_ANNOTATION_XML == elementName &&
4244 annotationXmlEncodingPermitsHtml(attributes)) {
4245 markAsHtmlIntegrationPoint = true;
4247 nsIContentHandle* elt;
4248 nsHtml5StackNode* current = stack[currentPtr];
4249 if (current->isFosterParenting()) {
4250 elt = createAndInsertFosterParentedElement(
4251 kNameSpaceID_MathML, popName, attributes, htmlCreator(nullptr));
4252 } else {
4253 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4254 elt = createElement(kNameSpaceID_MathML, popName, attributes, currentNode,
4255 htmlCreator(nullptr));
4256 appendElement(elt, currentNode);
4258 nsHtml5StackNode* node =
4259 createStackNode(elementName, elt, popName, markAsHtmlIntegrationPoint);
4260 push(node);
4263 bool nsHtml5TreeBuilder::annotationXmlEncodingPermitsHtml(
4264 nsHtml5HtmlAttributes* attributes) {
4265 nsHtml5String encoding =
4266 attributes->getValue(nsHtml5AttributeName::ATTR_ENCODING);
4267 if (!encoding) {
4268 return false;
4270 return nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
4271 "application/xhtml+xml", encoding) ||
4272 nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
4273 "text/html", encoding);
4276 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterSVG(
4277 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4278 nsAtom* popName = elementName->getCamelCaseName();
4279 nsIContentHandle* elt;
4280 nsHtml5StackNode* current = stack[currentPtr];
4281 if (current->isFosterParenting()) {
4282 elt = createAndInsertFosterParentedElement(
4283 kNameSpaceID_SVG, popName, attributes,
4284 svgCreator(elementName->getSvgCreator()));
4285 } else {
4286 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4287 elt = createElement(kNameSpaceID_SVG, popName, attributes, currentNode,
4288 svgCreator(elementName->getSvgCreator()));
4289 appendElement(elt, currentNode);
4291 nsHtml5StackNode* node = createStackNode(elementName, popName, elt);
4292 push(node);
4295 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(
4296 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes,
4297 nsIContentHandle* form) {
4298 nsIContentHandle* elt;
4299 nsIContentHandle* formOwner =
4300 !form || fragment || isTemplateContents() ? nullptr : form;
4301 nsHtml5StackNode* current = stack[currentPtr];
4302 if (current->isFosterParenting()) {
4303 elt = createAndInsertFosterParentedElement(
4304 kNameSpaceID_XHTML, elementName->getName(), attributes, formOwner,
4305 htmlCreator(elementName->getHtmlCreator()));
4306 } else {
4307 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4308 elt = createElement(kNameSpaceID_XHTML, elementName->getName(), attributes,
4309 formOwner, currentNode,
4310 htmlCreator(elementName->getHtmlCreator()));
4311 appendElement(elt, currentNode);
4313 nsHtml5StackNode* node = createStackNode(elementName, elt);
4314 push(node);
4317 void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFoster(
4318 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes,
4319 nsIContentHandle* form) {
4320 nsAtom* name = elementName->getName();
4321 nsIContentHandle* elt;
4322 nsIContentHandle* formOwner =
4323 !form || fragment || isTemplateContents() ? nullptr : form;
4324 nsHtml5StackNode* current = stack[currentPtr];
4325 if (current->isFosterParenting()) {
4326 elt = createAndInsertFosterParentedElement(
4327 kNameSpaceID_XHTML, name, attributes, formOwner,
4328 htmlCreator(elementName->getHtmlCreator()));
4329 } else {
4330 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4331 elt =
4332 createElement(kNameSpaceID_XHTML, name, attributes, formOwner,
4333 currentNode, htmlCreator(elementName->getHtmlCreator()));
4334 appendElement(elt, currentNode);
4336 elementPushed(kNameSpaceID_XHTML, name, elt);
4337 elementPopped(kNameSpaceID_XHTML, name, elt);
4340 void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFoster(
4341 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4342 nsAtom* popName = elementName->getName();
4343 nsIContentHandle* elt;
4344 nsHtml5StackNode* current = stack[currentPtr];
4345 if (current->isFosterParenting()) {
4346 elt = createAndInsertFosterParentedElement(
4347 kNameSpaceID_XHTML, popName, attributes,
4348 htmlCreator(elementName->getHtmlCreator()));
4349 } else {
4350 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4351 elt = createElement(kNameSpaceID_XHTML, popName, attributes, currentNode,
4352 htmlCreator(elementName->getHtmlCreator()));
4353 appendElement(elt, currentNode);
4355 elementPushed(kNameSpaceID_XHTML, popName, elt);
4356 elementPopped(kNameSpaceID_XHTML, popName, elt);
4359 void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFosterSVG(
4360 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4361 nsAtom* popName = elementName->getCamelCaseName();
4362 nsIContentHandle* elt;
4363 nsHtml5StackNode* current = stack[currentPtr];
4364 if (current->isFosterParenting()) {
4365 elt = createAndInsertFosterParentedElement(
4366 kNameSpaceID_SVG, popName, attributes,
4367 svgCreator(elementName->getSvgCreator()));
4368 } else {
4369 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4370 elt = createElement(kNameSpaceID_SVG, popName, attributes, currentNode,
4371 svgCreator(elementName->getSvgCreator()));
4372 appendElement(elt, currentNode);
4374 elementPushed(kNameSpaceID_SVG, popName, elt);
4375 elementPopped(kNameSpaceID_SVG, popName, elt);
4378 void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFosterMathML(
4379 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4380 nsAtom* popName = elementName->getName();
4381 nsIContentHandle* elt;
4382 nsHtml5StackNode* current = stack[currentPtr];
4383 if (current->isFosterParenting()) {
4384 elt = createAndInsertFosterParentedElement(
4385 kNameSpaceID_MathML, popName, attributes, htmlCreator(nullptr));
4386 } else {
4387 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4388 elt = createElement(kNameSpaceID_MathML, popName, attributes, currentNode,
4389 htmlCreator(nullptr));
4390 appendElement(elt, currentNode);
4392 elementPushed(kNameSpaceID_MathML, popName, elt);
4393 elementPopped(kNameSpaceID_MathML, popName, elt);
4396 void nsHtml5TreeBuilder::appendVoidInputToCurrent(
4397 nsHtml5HtmlAttributes* attributes, nsIContentHandle* form) {
4398 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4399 nsIContentHandle* elt =
4400 createElement(kNameSpaceID_XHTML, nsGkAtoms::input, attributes,
4401 !form || fragment || isTemplateContents() ? nullptr : form,
4402 currentNode, htmlCreator(NS_NewHTMLInputElement));
4403 appendElement(elt, currentNode);
4404 elementPushed(kNameSpaceID_XHTML, nsGkAtoms::input, elt);
4405 elementPopped(kNameSpaceID_XHTML, nsGkAtoms::input, elt);
4408 void nsHtml5TreeBuilder::appendVoidFormToCurrent(
4409 nsHtml5HtmlAttributes* attributes) {
4410 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4411 nsIContentHandle* elt =
4412 createElement(kNameSpaceID_XHTML, nsGkAtoms::form, attributes,
4413 currentNode, htmlCreator(NS_NewHTMLFormElement));
4414 formPointer = elt;
4415 appendElement(elt, currentNode);
4416 elementPushed(kNameSpaceID_XHTML, nsGkAtoms::form, elt);
4417 elementPopped(kNameSpaceID_XHTML, nsGkAtoms::form, elt);
4420 void nsHtml5TreeBuilder::requestSuspension() {
4421 tokenizer->requestSuspension();
4425 bool nsHtml5TreeBuilder::isInForeign() {
4426 return currentPtr >= 0 && stack[currentPtr]->ns != kNameSpaceID_XHTML;
4429 bool nsHtml5TreeBuilder::isInForeignButNotHtmlOrMathTextIntegrationPoint() {
4430 if (currentPtr < 0) {
4431 return false;
4433 return !isSpecialParentInForeign(stack[currentPtr]);
4436 void nsHtml5TreeBuilder::setFragmentContext(nsAtom* context, int32_t ns,
4437 nsIContentHandle* node,
4438 bool quirks) {
4439 this->contextName = context;
4440 this->contextNamespace = ns;
4441 this->contextNode = node;
4442 this->fragment = (!!contextName);
4443 this->quirks = quirks;
4446 nsIContentHandle* nsHtml5TreeBuilder::currentNode() {
4447 return stack[currentPtr]->node;
4450 bool nsHtml5TreeBuilder::isScriptingEnabled() { return scriptingEnabled; }
4452 void nsHtml5TreeBuilder::setScriptingEnabled(bool scriptingEnabled) {
4453 this->scriptingEnabled = scriptingEnabled;
4456 void nsHtml5TreeBuilder::setIsSrcdocDocument(bool isSrcdocDocument) {
4457 this->isSrcdocDocument = isSrcdocDocument;
4460 void nsHtml5TreeBuilder::flushCharacters() {
4461 if (charBufferLen > 0) {
4462 if ((mode == IN_TABLE || mode == IN_TABLE_BODY || mode == IN_ROW) &&
4463 charBufferContainsNonWhitespace()) {
4464 errNonSpaceInTable();
4465 reconstructTheActiveFormattingElements();
4466 if (!stack[currentPtr]->isFosterParenting()) {
4467 appendCharacters(currentNode(), charBuffer, 0, charBufferLen);
4468 charBufferLen = 0;
4469 return;
4471 int32_t tablePos = findLastOrRoot(nsHtml5TreeBuilder::TABLE);
4472 int32_t templatePos = findLastOrRoot(nsHtml5TreeBuilder::TEMPLATE);
4473 if (templatePos >= tablePos) {
4474 appendCharacters(stack[templatePos]->node, charBuffer, 0,
4475 charBufferLen);
4476 charBufferLen = 0;
4477 return;
4479 nsHtml5StackNode* tableElt = stack[tablePos];
4480 insertFosterParentedCharacters(charBuffer, 0, charBufferLen,
4481 tableElt->node, stack[tablePos - 1]->node);
4482 charBufferLen = 0;
4483 return;
4485 appendCharacters(currentNode(), charBuffer, 0, charBufferLen);
4486 charBufferLen = 0;
4490 bool nsHtml5TreeBuilder::charBufferContainsNonWhitespace() {
4491 for (int32_t i = 0; i < charBufferLen; i++) {
4492 switch (charBuffer[i]) {
4493 case ' ':
4494 case '\t':
4495 case '\n':
4496 case '\r':
4497 case '\f': {
4498 continue;
4500 default: {
4501 return true;
4505 return false;
4508 nsAHtml5TreeBuilderState* nsHtml5TreeBuilder::newSnapshot() {
4509 jArray<nsHtml5StackNode*, int32_t> listCopy =
4510 jArray<nsHtml5StackNode*, int32_t>::newJArray(listPtr + 1);
4511 for (int32_t i = 0; i < listCopy.length; i++) {
4512 nsHtml5StackNode* node = listOfActiveFormattingElements[i];
4513 if (node) {
4514 nsHtml5StackNode* newNode = new nsHtml5StackNode(-1);
4515 newNode->setValues(node->getFlags(), node->ns, node->name, node->node,
4516 node->popName, node->attributes->cloneAttributes(),
4517 node->getHtmlCreator());
4518 listCopy[i] = newNode;
4519 } else {
4520 listCopy[i] = nullptr;
4523 jArray<nsHtml5StackNode*, int32_t> stackCopy =
4524 jArray<nsHtml5StackNode*, int32_t>::newJArray(currentPtr + 1);
4525 for (int32_t i = 0; i < stackCopy.length; i++) {
4526 nsHtml5StackNode* node = stack[i];
4527 int32_t listIndex = findInListOfActiveFormattingElements(node);
4528 if (listIndex == -1) {
4529 nsHtml5StackNode* newNode = new nsHtml5StackNode(-1);
4530 newNode->setValues(node->getFlags(), node->ns, node->name, node->node,
4531 node->popName, nullptr, node->getHtmlCreator());
4532 stackCopy[i] = newNode;
4533 } else {
4534 stackCopy[i] = listCopy[listIndex];
4535 stackCopy[i]->retain();
4538 jArray<int32_t, int32_t> templateModeStackCopy =
4539 jArray<int32_t, int32_t>::newJArray(templateModePtr + 1);
4540 nsHtml5ArrayCopy::arraycopy(templateModeStack, templateModeStackCopy,
4541 templateModeStackCopy.length);
4542 return new nsHtml5StateSnapshot(stackCopy, listCopy, templateModeStackCopy,
4543 formPointer, headPointer, mode, originalMode,
4544 framesetOk, needToDropLF, quirks);
4547 bool nsHtml5TreeBuilder::snapshotMatches(nsAHtml5TreeBuilderState* snapshot) {
4548 jArray<nsHtml5StackNode*, int32_t> stackCopy = snapshot->getStack();
4549 int32_t stackLen = snapshot->getStackLength();
4550 jArray<nsHtml5StackNode*, int32_t> listCopy =
4551 snapshot->getListOfActiveFormattingElements();
4552 int32_t listLen = snapshot->getListOfActiveFormattingElementsLength();
4553 jArray<int32_t, int32_t> templateModeStackCopy =
4554 snapshot->getTemplateModeStack();
4555 int32_t templateModeStackLen = snapshot->getTemplateModeStackLength();
4556 if (stackLen != currentPtr + 1 || listLen != listPtr + 1 ||
4557 templateModeStackLen != templateModePtr + 1 ||
4558 formPointer != snapshot->getFormPointer() ||
4559 headPointer != snapshot->getHeadPointer() ||
4560 mode != snapshot->getMode() ||
4561 originalMode != snapshot->getOriginalMode() ||
4562 framesetOk != snapshot->isFramesetOk() ||
4563 needToDropLF != snapshot->isNeedToDropLF() ||
4564 quirks != snapshot->isQuirks()) {
4565 return false;
4567 for (int32_t i = listLen - 1; i >= 0; i--) {
4568 if (!listCopy[i] && !listOfActiveFormattingElements[i]) {
4569 continue;
4570 } else if (!listCopy[i] || !listOfActiveFormattingElements[i]) {
4571 return false;
4573 if (listCopy[i]->node != listOfActiveFormattingElements[i]->node) {
4574 return false;
4577 for (int32_t i = stackLen - 1; i >= 0; i--) {
4578 if (stackCopy[i]->node != stack[i]->node) {
4579 return false;
4582 for (int32_t i = templateModeStackLen - 1; i >= 0; i--) {
4583 if (templateModeStackCopy[i] != templateModeStack[i]) {
4584 return false;
4587 return true;
4590 void nsHtml5TreeBuilder::loadState(nsAHtml5TreeBuilderState* snapshot) {
4591 mCurrentHtmlScriptIsAsyncOrDefer = false;
4592 jArray<nsHtml5StackNode*, int32_t> stackCopy = snapshot->getStack();
4593 int32_t stackLen = snapshot->getStackLength();
4594 jArray<nsHtml5StackNode*, int32_t> listCopy =
4595 snapshot->getListOfActiveFormattingElements();
4596 int32_t listLen = snapshot->getListOfActiveFormattingElementsLength();
4597 jArray<int32_t, int32_t> templateModeStackCopy =
4598 snapshot->getTemplateModeStack();
4599 int32_t templateModeStackLen = snapshot->getTemplateModeStackLength();
4600 for (int32_t i = 0; i <= listPtr; i++) {
4601 if (listOfActiveFormattingElements[i]) {
4602 listOfActiveFormattingElements[i]->release(this);
4605 if (listOfActiveFormattingElements.length < listLen) {
4606 listOfActiveFormattingElements =
4607 jArray<nsHtml5StackNode*, int32_t>::newJArray(listLen);
4609 listPtr = listLen - 1;
4610 for (int32_t i = 0; i <= currentPtr; i++) {
4611 stack[i]->release(this);
4613 if (stack.length < stackLen) {
4614 stack = jArray<nsHtml5StackNode*, int32_t>::newJArray(stackLen);
4616 currentPtr = stackLen - 1;
4617 if (templateModeStack.length < templateModeStackLen) {
4618 templateModeStack =
4619 jArray<int32_t, int32_t>::newJArray(templateModeStackLen);
4621 templateModePtr = templateModeStackLen - 1;
4622 for (int32_t i = 0; i < listLen; i++) {
4623 nsHtml5StackNode* node = listCopy[i];
4624 if (node) {
4625 nsHtml5StackNode* newNode = createStackNode(
4626 node->getFlags(), node->ns, node->name, node->node, node->popName,
4627 node->attributes->cloneAttributes(), node->getHtmlCreator());
4628 listOfActiveFormattingElements[i] = newNode;
4629 } else {
4630 listOfActiveFormattingElements[i] = nullptr;
4633 for (int32_t i = 0; i < stackLen; i++) {
4634 nsHtml5StackNode* node = stackCopy[i];
4635 int32_t listIndex = findInArray(node, listCopy);
4636 if (listIndex == -1) {
4637 nsHtml5StackNode* newNode =
4638 createStackNode(node->getFlags(), node->ns, node->name, node->node,
4639 node->popName, nullptr, node->getHtmlCreator());
4640 stack[i] = newNode;
4641 } else {
4642 stack[i] = listOfActiveFormattingElements[listIndex];
4643 stack[i]->retain();
4646 nsHtml5ArrayCopy::arraycopy(templateModeStackCopy, templateModeStack,
4647 templateModeStackLen);
4648 formPointer = snapshot->getFormPointer();
4649 headPointer = snapshot->getHeadPointer();
4650 mode = snapshot->getMode();
4651 originalMode = snapshot->getOriginalMode();
4652 framesetOk = snapshot->isFramesetOk();
4653 needToDropLF = snapshot->isNeedToDropLF();
4654 quirks = snapshot->isQuirks();
4657 int32_t nsHtml5TreeBuilder::findInArray(
4658 nsHtml5StackNode* node, jArray<nsHtml5StackNode*, int32_t> arr) {
4659 for (int32_t i = listPtr; i >= 0; i--) {
4660 if (node == arr[i]) {
4661 return i;
4664 return -1;
4667 nsIContentHandle* nsHtml5TreeBuilder::nodeFromStackWithBlinkCompat(
4668 int32_t stackPos) {
4669 if (stackPos > 511) {
4670 errDeepTree();
4671 return stack[511]->node;
4673 return stack[stackPos]->node;
4676 nsIContentHandle* nsHtml5TreeBuilder::getFormPointer() { return formPointer; }
4678 nsIContentHandle* nsHtml5TreeBuilder::getHeadPointer() { return headPointer; }
4680 jArray<nsHtml5StackNode*, int32_t>
4681 nsHtml5TreeBuilder::getListOfActiveFormattingElements() {
4682 return listOfActiveFormattingElements;
4685 jArray<nsHtml5StackNode*, int32_t> nsHtml5TreeBuilder::getStack() {
4686 return stack;
4689 jArray<int32_t, int32_t> nsHtml5TreeBuilder::getTemplateModeStack() {
4690 return templateModeStack;
4693 int32_t nsHtml5TreeBuilder::getMode() { return mode; }
4695 int32_t nsHtml5TreeBuilder::getOriginalMode() { return originalMode; }
4697 bool nsHtml5TreeBuilder::isFramesetOk() { return framesetOk; }
4699 bool nsHtml5TreeBuilder::isNeedToDropLF() { return needToDropLF; }
4701 bool nsHtml5TreeBuilder::isQuirks() { return quirks; }
4703 int32_t nsHtml5TreeBuilder::getListOfActiveFormattingElementsLength() {
4704 return listPtr + 1;
4707 int32_t nsHtml5TreeBuilder::getStackLength() { return currentPtr + 1; }
4709 int32_t nsHtml5TreeBuilder::getTemplateModeStackLength() {
4710 return templateModePtr + 1;
4713 void nsHtml5TreeBuilder::initializeStatics() {}
4715 void nsHtml5TreeBuilder::releaseStatics() {}
4717 #include "nsHtml5TreeBuilderCppSupplement.h"