Bug 1647875 [wpt PR 24320] - [AspectRatio] Add an in-flow test for computing a block...
[gecko.git] / parser / html / nsHtml5TreeBuilder.cpp
blobfb5296ef2b64fe82488fbdbd1b7a72713b270ee3
1 /*
2 * Copyright (c) 2007 Henri Sivonen
3 * Copyright (c) 2007-2015 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 false);
240 } else if (isAlmostStandards(publicIdentifier, systemIdentifier)) {
241 errAlmostStandardsDoctype();
242 documentModeInternal(ALMOST_STANDARDS_MODE, publicIdentifier,
243 systemIdentifier, false);
244 } else {
245 documentModeInternal(STANDARDS_MODE, publicIdentifier, systemIdentifier,
246 false);
248 mode = BEFORE_HTML;
249 return;
251 errStrayDoctype();
252 return;
255 void nsHtml5TreeBuilder::comment(char16_t* buf, int32_t start, int32_t length) {
256 needToDropLF = false;
257 if (!isInForeign()) {
258 switch (mode) {
259 case INITIAL:
260 case BEFORE_HTML:
261 case AFTER_AFTER_BODY:
262 case AFTER_AFTER_FRAMESET: {
263 appendCommentToDocument(buf, start, length);
264 return;
266 case AFTER_BODY: {
267 flushCharacters();
268 appendComment(stack[0]->node, buf, start, length);
269 return;
271 default: {
272 break;
276 flushCharacters();
277 appendComment(stack[currentPtr]->node, buf, start, length);
278 return;
281 void nsHtml5TreeBuilder::characters(const char16_t* buf, int32_t start,
282 int32_t length) {
283 if (tokenizer->isViewingXmlSource()) {
284 return;
286 if (needToDropLF) {
287 needToDropLF = false;
288 if (buf[start] == '\n') {
289 start++;
290 length--;
291 if (!length) {
292 return;
296 switch (mode) {
297 case IN_BODY:
298 case IN_CELL:
299 case IN_CAPTION: {
300 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
301 reconstructTheActiveFormattingElements();
303 [[fallthrough]];
305 case TEXT: {
306 accumulateCharacters(buf, start, length);
307 return;
309 case IN_TABLE:
310 case IN_TABLE_BODY:
311 case IN_ROW: {
312 accumulateCharactersForced(buf, start, length);
313 return;
315 default: {
316 int32_t end = start + length;
317 for (int32_t i = start; i < end; i++) {
318 switch (buf[i]) {
319 case ' ':
320 case '\t':
321 case '\n':
322 case '\r':
323 case '\f': {
324 switch (mode) {
325 case INITIAL:
326 case BEFORE_HTML:
327 case BEFORE_HEAD: {
328 start = i + 1;
329 continue;
331 case IN_HEAD:
332 case IN_HEAD_NOSCRIPT:
333 case AFTER_HEAD:
334 case IN_COLUMN_GROUP:
335 case IN_FRAMESET:
336 case AFTER_FRAMESET: {
337 continue;
339 case FRAMESET_OK:
340 case IN_TEMPLATE:
341 case IN_BODY:
342 case IN_CELL:
343 case IN_CAPTION: {
344 if (start < i) {
345 accumulateCharacters(buf, start, i - start);
346 start = i;
348 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
349 flushCharacters();
350 reconstructTheActiveFormattingElements();
352 NS_HTML5_BREAK(charactersloop);
354 case IN_SELECT:
355 case IN_SELECT_IN_TABLE: {
356 NS_HTML5_BREAK(charactersloop);
358 case IN_TABLE:
359 case IN_TABLE_BODY:
360 case IN_ROW: {
361 accumulateCharactersForced(buf, i, 1);
362 start = i + 1;
363 continue;
365 case AFTER_BODY:
366 case AFTER_AFTER_BODY:
367 case AFTER_AFTER_FRAMESET: {
368 if (start < i) {
369 accumulateCharacters(buf, start, i - start);
370 start = i;
372 flushCharacters();
373 reconstructTheActiveFormattingElements();
374 continue;
377 MOZ_FALLTHROUGH_ASSERT();
379 default: {
380 switch (mode) {
381 case INITIAL: {
382 documentModeInternal(QUIRKS_MODE, nullptr, nullptr, false);
383 mode = BEFORE_HTML;
384 i--;
385 continue;
387 case BEFORE_HTML: {
388 appendHtmlElementToDocumentAndPush();
389 mode = BEFORE_HEAD;
390 i--;
391 continue;
393 case BEFORE_HEAD: {
394 if (start < i) {
395 accumulateCharacters(buf, start, i - start);
396 start = i;
398 flushCharacters();
399 appendToCurrentNodeAndPushHeadElement(
400 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
401 mode = IN_HEAD;
402 i--;
403 continue;
405 case IN_HEAD: {
406 if (start < i) {
407 accumulateCharacters(buf, start, i - start);
408 start = i;
410 flushCharacters();
411 pop();
412 mode = AFTER_HEAD;
413 i--;
414 continue;
416 case IN_HEAD_NOSCRIPT: {
417 if (start < i) {
418 accumulateCharacters(buf, start, i - start);
419 start = i;
421 errNonSpaceInNoscriptInHead();
422 flushCharacters();
423 pop();
424 mode = IN_HEAD;
425 i--;
426 continue;
428 case AFTER_HEAD: {
429 if (start < i) {
430 accumulateCharacters(buf, start, i - start);
431 start = i;
433 flushCharacters();
434 appendToCurrentNodeAndPushBodyElement();
435 mode = FRAMESET_OK;
436 i--;
437 continue;
439 case FRAMESET_OK: {
440 framesetOk = false;
441 mode = IN_BODY;
442 i--;
443 continue;
445 case IN_TEMPLATE:
446 case IN_BODY:
447 case IN_CELL:
448 case IN_CAPTION: {
449 if (start < i) {
450 accumulateCharacters(buf, start, i - start);
451 start = i;
453 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
454 flushCharacters();
455 reconstructTheActiveFormattingElements();
457 NS_HTML5_BREAK(charactersloop);
459 case IN_TABLE:
460 case IN_TABLE_BODY:
461 case IN_ROW: {
462 accumulateCharactersForced(buf, i, 1);
463 start = i + 1;
464 continue;
466 case IN_COLUMN_GROUP: {
467 if (start < i) {
468 accumulateCharacters(buf, start, i - start);
469 start = i;
471 if (!currentPtr || stack[currentPtr]->getGroup() ==
472 nsHtml5TreeBuilder::TEMPLATE) {
473 errNonSpaceInColgroupInFragment();
474 start = i + 1;
475 continue;
477 flushCharacters();
478 pop();
479 mode = IN_TABLE;
480 i--;
481 continue;
483 case IN_SELECT:
484 case IN_SELECT_IN_TABLE: {
485 NS_HTML5_BREAK(charactersloop);
487 case AFTER_BODY: {
488 errNonSpaceAfterBody();
490 mode = framesetOk ? FRAMESET_OK : IN_BODY;
491 i--;
492 continue;
494 case IN_FRAMESET: {
495 if (start < i) {
496 accumulateCharacters(buf, start, i - start);
498 errNonSpaceInFrameset();
499 start = i + 1;
500 continue;
502 case AFTER_FRAMESET: {
503 if (start < i) {
504 accumulateCharacters(buf, start, i - start);
506 errNonSpaceAfterFrameset();
507 start = i + 1;
508 continue;
510 case AFTER_AFTER_BODY: {
511 errNonSpaceInTrailer();
512 mode = framesetOk ? FRAMESET_OK : IN_BODY;
513 i--;
514 continue;
516 case AFTER_AFTER_FRAMESET: {
517 if (start < i) {
518 accumulateCharacters(buf, start, i - start);
520 errNonSpaceInTrailer();
521 start = i + 1;
522 continue;
528 charactersloop_end:;
529 if (start < end) {
530 accumulateCharacters(buf, start, end - start);
536 void nsHtml5TreeBuilder::zeroOriginatingReplacementCharacter() {
537 if (mode == TEXT) {
538 accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1);
539 return;
541 if (currentPtr >= 0) {
542 if (isSpecialParentInForeign(stack[currentPtr])) {
543 return;
545 accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1);
549 void nsHtml5TreeBuilder::eof() {
550 flushCharacters();
551 for (;;) {
552 switch (mode) {
553 case INITIAL: {
554 documentModeInternal(QUIRKS_MODE, nullptr, nullptr, false);
555 mode = BEFORE_HTML;
556 continue;
558 case BEFORE_HTML: {
559 appendHtmlElementToDocumentAndPush();
560 mode = BEFORE_HEAD;
561 continue;
563 case BEFORE_HEAD: {
564 appendToCurrentNodeAndPushHeadElement(
565 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
566 mode = IN_HEAD;
567 continue;
569 case IN_HEAD: {
570 while (currentPtr > 0) {
571 popOnEof();
573 mode = AFTER_HEAD;
574 continue;
576 case IN_HEAD_NOSCRIPT: {
577 while (currentPtr > 1) {
578 popOnEof();
580 mode = IN_HEAD;
581 continue;
583 case AFTER_HEAD: {
584 appendToCurrentNodeAndPushBodyElement();
585 mode = IN_BODY;
586 continue;
588 case IN_TABLE_BODY:
589 case IN_ROW:
590 case IN_TABLE:
591 case IN_SELECT_IN_TABLE:
592 case IN_SELECT:
593 case IN_COLUMN_GROUP:
594 case FRAMESET_OK:
595 case IN_CAPTION:
596 case IN_CELL:
597 case IN_BODY: {
598 if (isTemplateModeStackEmpty()) {
599 NS_HTML5_BREAK(eofloop);
601 [[fallthrough]];
603 case IN_TEMPLATE: {
604 int32_t eltPos = findLast(nsGkAtoms::_template);
605 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
606 MOZ_ASSERT(fragment);
607 NS_HTML5_BREAK(eofloop);
609 if (MOZ_UNLIKELY(mViewSource)) {
610 errUnclosedElements(eltPos, nsGkAtoms::_template);
612 while (currentPtr >= eltPos) {
613 pop();
615 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
616 popTemplateMode();
617 resetTheInsertionMode();
618 continue;
620 case TEXT: {
621 if (originalMode == AFTER_HEAD) {
622 popOnEof();
624 popOnEof();
625 mode = originalMode;
626 continue;
628 case IN_FRAMESET: {
629 NS_HTML5_BREAK(eofloop);
631 case AFTER_BODY:
632 case AFTER_FRAMESET:
633 case AFTER_AFTER_BODY:
634 case AFTER_AFTER_FRAMESET:
635 default: {
636 NS_HTML5_BREAK(eofloop);
640 eofloop_end:;
641 while (currentPtr > 0) {
642 popOnEof();
644 if (!fragment) {
645 popOnEof();
649 void nsHtml5TreeBuilder::endTokenization() {
650 formPointer = nullptr;
651 headPointer = nullptr;
652 contextName = nullptr;
653 contextNode = nullptr;
654 templateModeStack = nullptr;
655 if (stack) {
656 while (currentPtr > -1) {
657 stack[currentPtr]->release(this);
658 currentPtr--;
660 stack = nullptr;
662 if (listOfActiveFormattingElements) {
663 while (listPtr > -1) {
664 if (listOfActiveFormattingElements[listPtr]) {
665 listOfActiveFormattingElements[listPtr]->release(this);
667 listPtr--;
669 listOfActiveFormattingElements = nullptr;
671 if (stackNodes) {
672 for (int32_t i = 0; i < numStackNodes; i++) {
673 MOZ_ASSERT(stackNodes[i]->isUnused());
674 delete stackNodes[i];
676 numStackNodes = 0;
677 stackNodesIdx = 0;
678 stackNodes = nullptr;
680 charBuffer = nullptr;
681 end();
684 void nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName,
685 nsHtml5HtmlAttributes* attributes,
686 bool selfClosing) {
687 flushCharacters();
688 int32_t eltPos;
689 needToDropLF = false;
690 starttagloop:
691 for (;;) {
692 int32_t group = elementName->getGroup();
693 nsAtom* name = elementName->getName();
694 if (isInForeign()) {
695 nsHtml5StackNode* currentNode = stack[currentPtr];
696 int32_t currNs = currentNode->ns;
697 if (!(currentNode->isHtmlIntegrationPoint() ||
698 (currNs == kNameSpaceID_MathML &&
699 ((currentNode->getGroup() == MI_MO_MN_MS_MTEXT &&
700 group != MGLYPH_OR_MALIGNMARK) ||
701 (currentNode->getGroup() == ANNOTATION_XML && group == SVG))))) {
702 switch (group) {
703 case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
704 case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
705 case BODY:
706 case BR:
707 case RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR:
708 case DD_OR_DT:
709 case UL_OR_OL_OR_DL:
710 case EMBED:
711 case IMG:
712 case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6:
713 case HEAD:
714 case HR:
715 case LI:
716 case META:
717 case NOBR:
718 case P:
719 case PRE_OR_LISTING:
720 case TABLE:
721 case FONT: {
722 if (!(group == FONT &&
723 !(attributes->contains(nsHtml5AttributeName::ATTR_COLOR) ||
724 attributes->contains(nsHtml5AttributeName::ATTR_FACE) ||
725 attributes->contains(nsHtml5AttributeName::ATTR_SIZE)))) {
726 errHtmlStartTagInForeignContext(name);
727 if (!fragment) {
728 while (!isSpecialParentInForeign(stack[currentPtr])) {
729 popForeign(-1, -1);
731 NS_HTML5_CONTINUE(starttagloop);
734 [[fallthrough]];
736 default: {
737 if (kNameSpaceID_SVG == currNs) {
738 attributes->adjustForSvg();
739 if (selfClosing) {
740 appendVoidElementToCurrentMayFosterSVG(elementName, attributes);
741 selfClosing = false;
742 } else {
743 appendToCurrentNodeAndPushElementMayFosterSVG(elementName,
744 attributes);
746 attributes = nullptr;
747 NS_HTML5_BREAK(starttagloop);
748 } else {
749 attributes->adjustForMath();
750 if (selfClosing) {
751 appendVoidElementToCurrentMayFosterMathML(elementName,
752 attributes);
753 selfClosing = false;
754 } else {
755 appendToCurrentNodeAndPushElementMayFosterMathML(elementName,
756 attributes);
758 attributes = nullptr;
759 NS_HTML5_BREAK(starttagloop);
765 switch (mode) {
766 case IN_TEMPLATE: {
767 switch (group) {
768 case COL: {
769 popTemplateMode();
770 pushTemplateMode(IN_COLUMN_GROUP);
771 mode = IN_COLUMN_GROUP;
772 continue;
774 case CAPTION:
775 case COLGROUP:
776 case TBODY_OR_THEAD_OR_TFOOT: {
777 popTemplateMode();
778 pushTemplateMode(IN_TABLE);
779 mode = IN_TABLE;
780 continue;
782 case TR: {
783 popTemplateMode();
784 pushTemplateMode(IN_TABLE_BODY);
785 mode = IN_TABLE_BODY;
786 continue;
788 case TD_OR_TH: {
789 popTemplateMode();
790 pushTemplateMode(IN_ROW);
791 mode = IN_ROW;
792 continue;
794 case META: {
795 checkMetaCharset(attributes);
796 appendVoidElementToCurrentMayFoster(elementName, attributes);
797 selfClosing = false;
798 attributes = nullptr;
799 NS_HTML5_BREAK(starttagloop);
801 case TITLE: {
802 startTagTitleInHead(elementName, attributes);
803 attributes = nullptr;
804 NS_HTML5_BREAK(starttagloop);
806 case BASE:
807 case LINK_OR_BASEFONT_OR_BGSOUND: {
808 appendVoidElementToCurrentMayFoster(elementName, attributes);
809 selfClosing = false;
810 attributes = nullptr;
811 NS_HTML5_BREAK(starttagloop);
813 case SCRIPT: {
814 startTagScriptInHead(elementName, attributes);
815 attributes = nullptr;
816 NS_HTML5_BREAK(starttagloop);
818 case NOFRAMES:
819 case STYLE: {
820 startTagGenericRawText(elementName, attributes);
821 attributes = nullptr;
822 NS_HTML5_BREAK(starttagloop);
824 case TEMPLATE: {
825 startTagTemplateInHead(elementName, attributes);
826 attributes = nullptr;
827 NS_HTML5_BREAK(starttagloop);
829 default: {
830 popTemplateMode();
831 pushTemplateMode(IN_BODY);
832 mode = IN_BODY;
833 continue;
837 case IN_ROW: {
838 switch (group) {
839 case TD_OR_TH: {
840 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TR));
841 appendToCurrentNodeAndPushElement(elementName, attributes);
842 mode = IN_CELL;
843 insertMarker();
844 attributes = nullptr;
845 NS_HTML5_BREAK(starttagloop);
847 case CAPTION:
848 case COL:
849 case COLGROUP:
850 case TBODY_OR_THEAD_OR_TFOOT:
851 case TR: {
852 eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
853 if (!eltPos) {
854 MOZ_ASSERT(fragment || isTemplateContents());
855 errNoTableRowToClose();
856 NS_HTML5_BREAK(starttagloop);
858 clearStackBackTo(eltPos);
859 pop();
860 mode = IN_TABLE_BODY;
861 continue;
863 default:; // fall through
865 [[fallthrough]];
867 case IN_TABLE_BODY: {
868 switch (group) {
869 case TR: {
870 clearStackBackTo(
871 findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
872 appendToCurrentNodeAndPushElement(elementName, attributes);
873 mode = IN_ROW;
874 attributes = nullptr;
875 NS_HTML5_BREAK(starttagloop);
877 case TD_OR_TH: {
878 errStartTagInTableBody(name);
879 clearStackBackTo(
880 findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
881 appendToCurrentNodeAndPushElement(
882 nsHtml5ElementName::ELT_TR,
883 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
884 mode = IN_ROW;
885 continue;
887 case CAPTION:
888 case COL:
889 case COLGROUP:
890 case TBODY_OR_THEAD_OR_TFOOT: {
891 eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
892 if (!eltPos || stack[eltPos]->getGroup() == TEMPLATE) {
893 MOZ_ASSERT(fragment || isTemplateContents());
894 errStrayStartTag(name);
895 NS_HTML5_BREAK(starttagloop);
896 } else {
897 clearStackBackTo(eltPos);
898 pop();
899 mode = IN_TABLE;
900 continue;
903 default:; // fall through
905 [[fallthrough]];
907 case IN_TABLE: {
908 for (;;) {
909 switch (group) {
910 case CAPTION: {
911 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
912 insertMarker();
913 appendToCurrentNodeAndPushElement(elementName, attributes);
914 mode = IN_CAPTION;
915 attributes = nullptr;
916 NS_HTML5_BREAK(starttagloop);
918 case COLGROUP: {
919 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
920 appendToCurrentNodeAndPushElement(elementName, attributes);
921 mode = IN_COLUMN_GROUP;
922 attributes = nullptr;
923 NS_HTML5_BREAK(starttagloop);
925 case COL: {
926 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
927 appendToCurrentNodeAndPushElement(
928 nsHtml5ElementName::ELT_COLGROUP,
929 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
930 mode = IN_COLUMN_GROUP;
931 NS_HTML5_CONTINUE(starttagloop);
933 case TBODY_OR_THEAD_OR_TFOOT: {
934 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
935 appendToCurrentNodeAndPushElement(elementName, attributes);
936 mode = IN_TABLE_BODY;
937 attributes = nullptr;
938 NS_HTML5_BREAK(starttagloop);
940 case TR:
941 case TD_OR_TH: {
942 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
943 appendToCurrentNodeAndPushElement(
944 nsHtml5ElementName::ELT_TBODY,
945 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
946 mode = IN_TABLE_BODY;
947 NS_HTML5_CONTINUE(starttagloop);
949 case TEMPLATE: {
950 NS_HTML5_BREAK(intableloop);
952 case TABLE: {
953 errTableSeenWhileTableOpen();
954 eltPos = findLastInTableScope(name);
955 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
956 MOZ_ASSERT(fragment || isTemplateContents());
957 NS_HTML5_BREAK(starttagloop);
959 generateImpliedEndTags();
960 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(nsGkAtoms::table)) {
961 errNoCheckUnclosedElementsOnStack();
963 while (currentPtr >= eltPos) {
964 pop();
966 resetTheInsertionMode();
967 NS_HTML5_CONTINUE(starttagloop);
969 case SCRIPT: {
970 appendToCurrentNodeAndPushElement(elementName, attributes);
971 originalMode = mode;
972 mode = TEXT;
973 tokenizer->setStateAndEndTagExpectation(
974 nsHtml5Tokenizer::SCRIPT_DATA, elementName);
975 attributes = nullptr;
976 NS_HTML5_BREAK(starttagloop);
978 case STYLE: {
979 appendToCurrentNodeAndPushElement(elementName, attributes);
980 originalMode = mode;
981 mode = TEXT;
982 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
983 elementName);
984 attributes = nullptr;
985 NS_HTML5_BREAK(starttagloop);
987 case INPUT: {
988 errStartTagInTable(name);
989 if (!nsHtml5Portability::
990 lowerCaseLiteralEqualsIgnoreAsciiCaseString(
991 "hidden", attributes->getValue(
992 nsHtml5AttributeName::ATTR_TYPE))) {
993 NS_HTML5_BREAK(intableloop);
995 appendVoidInputToCurrent(attributes, formPointer);
996 selfClosing = false;
997 attributes = nullptr;
998 NS_HTML5_BREAK(starttagloop);
1000 case FORM: {
1001 if (!!formPointer || isTemplateContents()) {
1002 errFormWhenFormOpen();
1003 NS_HTML5_BREAK(starttagloop);
1004 } else {
1005 errStartTagInTable(name);
1006 appendVoidFormToCurrent(attributes);
1007 attributes = nullptr;
1008 NS_HTML5_BREAK(starttagloop);
1011 default: {
1012 errStartTagInTable(name);
1013 NS_HTML5_BREAK(intableloop);
1017 intableloop_end:;
1018 [[fallthrough]];
1020 case IN_CAPTION: {
1021 switch (group) {
1022 case CAPTION:
1023 case COL:
1024 case COLGROUP:
1025 case TBODY_OR_THEAD_OR_TFOOT:
1026 case TR:
1027 case TD_OR_TH: {
1028 errStrayStartTag(name);
1029 eltPos = findLastInTableScope(nsGkAtoms::caption);
1030 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1031 NS_HTML5_BREAK(starttagloop);
1033 generateImpliedEndTags();
1034 if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
1035 errNoCheckUnclosedElementsOnStack();
1037 while (currentPtr >= eltPos) {
1038 pop();
1040 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
1041 mode = IN_TABLE;
1042 continue;
1044 default:; // fall through
1046 [[fallthrough]];
1048 case IN_CELL: {
1049 switch (group) {
1050 case CAPTION:
1051 case COL:
1052 case COLGROUP:
1053 case TBODY_OR_THEAD_OR_TFOOT:
1054 case TR:
1055 case TD_OR_TH: {
1056 eltPos = findLastInTableScopeTdTh();
1057 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1058 errNoCellToClose();
1059 NS_HTML5_BREAK(starttagloop);
1060 } else {
1061 closeTheCell(eltPos);
1062 continue;
1065 default:; // fall through
1067 [[fallthrough]];
1069 case FRAMESET_OK: {
1070 switch (group) {
1071 case FRAMESET: {
1072 if (mode == FRAMESET_OK) {
1073 if (!currentPtr || stack[1]->getGroup() != BODY) {
1074 MOZ_ASSERT(fragment || isTemplateContents());
1075 errStrayStartTag(name);
1076 NS_HTML5_BREAK(starttagloop);
1077 } else {
1078 errFramesetStart();
1079 detachFromParent(stack[1]->node);
1080 while (currentPtr > 0) {
1081 pop();
1083 appendToCurrentNodeAndPushElement(elementName, attributes);
1084 mode = IN_FRAMESET;
1085 attributes = nullptr;
1086 NS_HTML5_BREAK(starttagloop);
1088 } else {
1089 errStrayStartTag(name);
1090 NS_HTML5_BREAK(starttagloop);
1093 case PRE_OR_LISTING:
1094 case LI:
1095 case DD_OR_DT:
1096 case BUTTON:
1097 case MARQUEE_OR_APPLET:
1098 case OBJECT:
1099 case TABLE:
1100 case AREA_OR_WBR:
1101 case KEYGEN:
1102 case BR:
1103 case EMBED:
1104 case IMG:
1105 case INPUT:
1106 case HR:
1107 case TEXTAREA:
1108 case XMP:
1109 case IFRAME:
1110 case SELECT: {
1111 if (mode == FRAMESET_OK &&
1112 !(group == INPUT &&
1113 nsHtml5Portability::
1114 lowerCaseLiteralEqualsIgnoreAsciiCaseString(
1115 "hidden", attributes->getValue(
1116 nsHtml5AttributeName::ATTR_TYPE)))) {
1117 framesetOk = false;
1118 mode = IN_BODY;
1120 [[fallthrough]];
1122 default:; // fall through
1124 [[fallthrough]];
1126 case IN_BODY: {
1127 for (;;) {
1128 switch (group) {
1129 case HTML: {
1130 errStrayStartTag(name);
1131 if (!fragment && !isTemplateContents()) {
1132 addAttributesToHtml(attributes);
1133 attributes = nullptr;
1135 NS_HTML5_BREAK(starttagloop);
1137 case BASE:
1138 case LINK_OR_BASEFONT_OR_BGSOUND:
1139 case META:
1140 case STYLE:
1141 case SCRIPT:
1142 case TITLE:
1143 case TEMPLATE: {
1144 NS_HTML5_BREAK(inbodyloop);
1146 case BODY: {
1147 if (!currentPtr || stack[1]->getGroup() != BODY ||
1148 isTemplateContents()) {
1149 MOZ_ASSERT(fragment || isTemplateContents());
1150 errStrayStartTag(name);
1151 NS_HTML5_BREAK(starttagloop);
1153 errFooSeenWhenFooOpen(name);
1154 framesetOk = false;
1155 if (mode == FRAMESET_OK) {
1156 mode = IN_BODY;
1158 if (addAttributesToBody(attributes)) {
1159 attributes = nullptr;
1161 NS_HTML5_BREAK(starttagloop);
1163 case P:
1164 case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
1165 case UL_OR_OL_OR_DL:
1166 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: {
1167 implicitlyCloseP();
1168 appendToCurrentNodeAndPushElementMayFoster(elementName,
1169 attributes);
1170 attributes = nullptr;
1171 NS_HTML5_BREAK(starttagloop);
1173 case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: {
1174 implicitlyCloseP();
1175 if (stack[currentPtr]->getGroup() ==
1176 H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
1177 errHeadingWhenHeadingOpen();
1178 pop();
1180 appendToCurrentNodeAndPushElementMayFoster(elementName,
1181 attributes);
1182 attributes = nullptr;
1183 NS_HTML5_BREAK(starttagloop);
1185 case FIELDSET: {
1186 implicitlyCloseP();
1187 appendToCurrentNodeAndPushElementMayFoster(
1188 elementName, attributes, formPointer);
1189 attributes = nullptr;
1190 NS_HTML5_BREAK(starttagloop);
1192 case PRE_OR_LISTING: {
1193 implicitlyCloseP();
1194 appendToCurrentNodeAndPushElementMayFoster(elementName,
1195 attributes);
1196 needToDropLF = true;
1197 attributes = nullptr;
1198 NS_HTML5_BREAK(starttagloop);
1200 case FORM: {
1201 if (!!formPointer && !isTemplateContents()) {
1202 errFormWhenFormOpen();
1203 NS_HTML5_BREAK(starttagloop);
1204 } else {
1205 implicitlyCloseP();
1206 appendToCurrentNodeAndPushFormElementMayFoster(attributes);
1207 attributes = nullptr;
1208 NS_HTML5_BREAK(starttagloop);
1211 case LI:
1212 case DD_OR_DT: {
1213 eltPos = currentPtr;
1214 for (;;) {
1215 nsHtml5StackNode* node = stack[eltPos];
1216 if (node->getGroup() == group) {
1217 generateImpliedEndTagsExceptFor(node->name);
1218 if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
1219 errUnclosedElementsImplied(eltPos, name);
1221 while (currentPtr >= eltPos) {
1222 pop();
1224 break;
1225 } else if (!eltPos || (node->isSpecial() &&
1226 (node->ns != kNameSpaceID_XHTML ||
1227 (node->name != nsGkAtoms::p &&
1228 node->name != nsGkAtoms::address &&
1229 node->name != nsGkAtoms::div)))) {
1230 break;
1232 eltPos--;
1234 implicitlyCloseP();
1235 appendToCurrentNodeAndPushElementMayFoster(elementName,
1236 attributes);
1237 attributes = nullptr;
1238 NS_HTML5_BREAK(starttagloop);
1240 case PLAINTEXT: {
1241 implicitlyCloseP();
1242 appendToCurrentNodeAndPushElementMayFoster(elementName,
1243 attributes);
1244 tokenizer->setStateAndEndTagExpectation(
1245 nsHtml5Tokenizer::PLAINTEXT, elementName);
1246 attributes = nullptr;
1247 NS_HTML5_BREAK(starttagloop);
1249 case A: {
1250 int32_t activeAPos =
1251 findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(
1252 nsGkAtoms::a);
1253 if (activeAPos != -1) {
1254 errFooSeenWhenFooOpen(name);
1255 nsHtml5StackNode* activeA =
1256 listOfActiveFormattingElements[activeAPos];
1257 activeA->retain();
1258 adoptionAgencyEndTag(nsGkAtoms::a);
1259 removeFromStack(activeA);
1260 activeAPos = findInListOfActiveFormattingElements(activeA);
1261 if (activeAPos != -1) {
1262 removeFromListOfActiveFormattingElements(activeAPos);
1264 activeA->release(this);
1266 reconstructTheActiveFormattingElements();
1267 appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
1268 attributes);
1269 attributes = nullptr;
1270 NS_HTML5_BREAK(starttagloop);
1272 case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
1273 case FONT: {
1274 reconstructTheActiveFormattingElements();
1275 maybeForgetEarlierDuplicateFormattingElement(
1276 elementName->getName(), attributes);
1277 appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
1278 attributes);
1279 attributes = nullptr;
1280 NS_HTML5_BREAK(starttagloop);
1282 case NOBR: {
1283 reconstructTheActiveFormattingElements();
1284 if (nsHtml5TreeBuilder::NOT_FOUND_ON_STACK !=
1285 findLastInScope(nsGkAtoms::nobr)) {
1286 errFooSeenWhenFooOpen(name);
1287 adoptionAgencyEndTag(nsGkAtoms::nobr);
1288 reconstructTheActiveFormattingElements();
1290 appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
1291 attributes);
1292 attributes = nullptr;
1293 NS_HTML5_BREAK(starttagloop);
1295 case BUTTON: {
1296 eltPos = findLastInScope(name);
1297 if (eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1298 errFooSeenWhenFooOpen(name);
1299 generateImpliedEndTags();
1300 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
1301 errUnclosedElementsImplied(eltPos, name);
1303 while (currentPtr >= eltPos) {
1304 pop();
1306 NS_HTML5_CONTINUE(starttagloop);
1307 } else {
1308 reconstructTheActiveFormattingElements();
1309 appendToCurrentNodeAndPushElementMayFoster(
1310 elementName, attributes, formPointer);
1311 attributes = nullptr;
1312 NS_HTML5_BREAK(starttagloop);
1315 case OBJECT: {
1316 reconstructTheActiveFormattingElements();
1317 appendToCurrentNodeAndPushElementMayFoster(
1318 elementName, attributes, formPointer);
1319 insertMarker();
1320 attributes = nullptr;
1321 NS_HTML5_BREAK(starttagloop);
1323 case MARQUEE_OR_APPLET: {
1324 reconstructTheActiveFormattingElements();
1325 appendToCurrentNodeAndPushElementMayFoster(elementName,
1326 attributes);
1327 insertMarker();
1328 attributes = nullptr;
1329 NS_HTML5_BREAK(starttagloop);
1331 case TABLE: {
1332 if (!quirks) {
1333 implicitlyCloseP();
1335 appendToCurrentNodeAndPushElementMayFoster(elementName,
1336 attributes);
1337 mode = IN_TABLE;
1338 attributes = nullptr;
1339 NS_HTML5_BREAK(starttagloop);
1341 case BR:
1342 case EMBED:
1343 case AREA_OR_WBR:
1344 case KEYGEN: {
1345 reconstructTheActiveFormattingElements();
1346 [[fallthrough]];
1348 #ifdef ENABLE_VOID_MENUITEM
1349 case MENUITEM:
1350 #endif
1351 case PARAM_OR_SOURCE_OR_TRACK: {
1352 appendVoidElementToCurrentMayFoster(elementName, attributes);
1353 selfClosing = false;
1354 attributes = nullptr;
1355 NS_HTML5_BREAK(starttagloop);
1357 case HR: {
1358 implicitlyCloseP();
1359 appendVoidElementToCurrentMayFoster(elementName, attributes);
1360 selfClosing = false;
1361 attributes = nullptr;
1362 NS_HTML5_BREAK(starttagloop);
1364 case IMAGE: {
1365 errImage();
1366 elementName = nsHtml5ElementName::ELT_IMG;
1367 NS_HTML5_CONTINUE(starttagloop);
1369 case IMG:
1370 case INPUT: {
1371 reconstructTheActiveFormattingElements();
1372 appendVoidElementToCurrentMayFoster(elementName, attributes,
1373 formPointer);
1374 selfClosing = false;
1375 attributes = nullptr;
1376 NS_HTML5_BREAK(starttagloop);
1378 case TEXTAREA: {
1379 appendToCurrentNodeAndPushElementMayFoster(
1380 elementName, attributes, formPointer);
1381 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
1382 elementName);
1383 originalMode = mode;
1384 mode = TEXT;
1385 needToDropLF = true;
1386 attributes = nullptr;
1387 NS_HTML5_BREAK(starttagloop);
1389 case XMP: {
1390 implicitlyCloseP();
1391 reconstructTheActiveFormattingElements();
1392 appendToCurrentNodeAndPushElementMayFoster(elementName,
1393 attributes);
1394 originalMode = mode;
1395 mode = TEXT;
1396 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1397 elementName);
1398 attributes = nullptr;
1399 NS_HTML5_BREAK(starttagloop);
1401 case NOSCRIPT: {
1402 if (!scriptingEnabled) {
1403 reconstructTheActiveFormattingElements();
1404 appendToCurrentNodeAndPushElementMayFoster(elementName,
1405 attributes);
1406 attributes = nullptr;
1407 NS_HTML5_BREAK(starttagloop);
1409 [[fallthrough]];
1411 case NOFRAMES:
1412 case IFRAME:
1413 case NOEMBED: {
1414 startTagGenericRawText(elementName, attributes);
1415 attributes = nullptr;
1416 NS_HTML5_BREAK(starttagloop);
1418 case SELECT: {
1419 reconstructTheActiveFormattingElements();
1420 appendToCurrentNodeAndPushElementMayFoster(
1421 elementName, attributes, formPointer);
1422 switch (mode) {
1423 case IN_TABLE:
1424 case IN_CAPTION:
1425 case IN_COLUMN_GROUP:
1426 case IN_TABLE_BODY:
1427 case IN_ROW:
1428 case IN_CELL: {
1429 mode = IN_SELECT_IN_TABLE;
1430 break;
1432 default: {
1433 mode = IN_SELECT;
1434 break;
1437 attributes = nullptr;
1438 NS_HTML5_BREAK(starttagloop);
1440 case OPTGROUP:
1441 case OPTION: {
1442 if (isCurrent(nsGkAtoms::option)) {
1443 pop();
1445 reconstructTheActiveFormattingElements();
1446 appendToCurrentNodeAndPushElementMayFoster(elementName,
1447 attributes);
1448 attributes = nullptr;
1449 NS_HTML5_BREAK(starttagloop);
1451 case RB_OR_RTC: {
1452 eltPos = findLastInScope(nsGkAtoms::ruby);
1453 if (eltPos != NOT_FOUND_ON_STACK) {
1454 generateImpliedEndTags();
1456 if (eltPos != currentPtr) {
1457 if (eltPos == NOT_FOUND_ON_STACK) {
1458 errStartTagSeenWithoutRuby(name);
1459 } else {
1460 errUnclosedChildrenInRuby();
1463 appendToCurrentNodeAndPushElementMayFoster(elementName,
1464 attributes);
1465 attributes = nullptr;
1466 NS_HTML5_BREAK(starttagloop);
1468 case RT_OR_RP: {
1469 eltPos = findLastInScope(nsGkAtoms::ruby);
1470 if (eltPos != NOT_FOUND_ON_STACK) {
1471 generateImpliedEndTagsExceptFor(nsGkAtoms::rtc);
1473 if (eltPos != currentPtr) {
1474 if (!isCurrent(nsGkAtoms::rtc)) {
1475 if (eltPos == NOT_FOUND_ON_STACK) {
1476 errStartTagSeenWithoutRuby(name);
1477 } else {
1478 errUnclosedChildrenInRuby();
1482 appendToCurrentNodeAndPushElementMayFoster(elementName,
1483 attributes);
1484 attributes = nullptr;
1485 NS_HTML5_BREAK(starttagloop);
1487 case MATH: {
1488 reconstructTheActiveFormattingElements();
1489 attributes->adjustForMath();
1490 if (selfClosing) {
1491 appendVoidElementToCurrentMayFosterMathML(elementName,
1492 attributes);
1493 selfClosing = false;
1494 } else {
1495 appendToCurrentNodeAndPushElementMayFosterMathML(elementName,
1496 attributes);
1498 attributes = nullptr;
1499 NS_HTML5_BREAK(starttagloop);
1501 case SVG: {
1502 reconstructTheActiveFormattingElements();
1503 attributes->adjustForSvg();
1504 if (selfClosing) {
1505 appendVoidElementToCurrentMayFosterSVG(elementName, attributes);
1506 selfClosing = false;
1507 } else {
1508 appendToCurrentNodeAndPushElementMayFosterSVG(elementName,
1509 attributes);
1511 attributes = nullptr;
1512 NS_HTML5_BREAK(starttagloop);
1514 case CAPTION:
1515 case COL:
1516 case COLGROUP:
1517 case TBODY_OR_THEAD_OR_TFOOT:
1518 case TR:
1519 case TD_OR_TH:
1520 case FRAME:
1521 case FRAMESET:
1522 case HEAD: {
1523 errStrayStartTag(name);
1524 NS_HTML5_BREAK(starttagloop);
1526 case OUTPUT: {
1527 reconstructTheActiveFormattingElements();
1528 appendToCurrentNodeAndPushElementMayFoster(
1529 elementName, attributes, formPointer);
1530 attributes = nullptr;
1531 NS_HTML5_BREAK(starttagloop);
1533 default: {
1534 reconstructTheActiveFormattingElements();
1535 appendToCurrentNodeAndPushElementMayFoster(elementName,
1536 attributes);
1537 attributes = nullptr;
1538 NS_HTML5_BREAK(starttagloop);
1542 inbodyloop_end:;
1543 [[fallthrough]];
1545 case IN_HEAD: {
1546 for (;;) {
1547 switch (group) {
1548 case HTML: {
1549 errStrayStartTag(name);
1550 if (!fragment && !isTemplateContents()) {
1551 addAttributesToHtml(attributes);
1552 attributes = nullptr;
1554 NS_HTML5_BREAK(starttagloop);
1556 case BASE:
1557 case LINK_OR_BASEFONT_OR_BGSOUND: {
1558 appendVoidElementToCurrentMayFoster(elementName, attributes);
1559 selfClosing = false;
1560 attributes = nullptr;
1561 NS_HTML5_BREAK(starttagloop);
1563 case META: {
1564 NS_HTML5_BREAK(inheadloop);
1566 case TITLE: {
1567 startTagTitleInHead(elementName, attributes);
1568 attributes = nullptr;
1569 NS_HTML5_BREAK(starttagloop);
1571 case NOSCRIPT: {
1572 if (scriptingEnabled) {
1573 appendToCurrentNodeAndPushElement(elementName, attributes);
1574 originalMode = mode;
1575 mode = TEXT;
1576 tokenizer->setStateAndEndTagExpectation(
1577 nsHtml5Tokenizer::RAWTEXT, elementName);
1578 } else {
1579 appendToCurrentNodeAndPushElementMayFoster(elementName,
1580 attributes);
1581 mode = IN_HEAD_NOSCRIPT;
1583 attributes = nullptr;
1584 NS_HTML5_BREAK(starttagloop);
1586 case SCRIPT: {
1587 startTagScriptInHead(elementName, attributes);
1588 attributes = nullptr;
1589 NS_HTML5_BREAK(starttagloop);
1591 case STYLE:
1592 case NOFRAMES: {
1593 startTagGenericRawText(elementName, attributes);
1594 attributes = nullptr;
1595 NS_HTML5_BREAK(starttagloop);
1597 case HEAD: {
1598 errFooSeenWhenFooOpen(name);
1599 NS_HTML5_BREAK(starttagloop);
1601 case TEMPLATE: {
1602 startTagTemplateInHead(elementName, attributes);
1603 attributes = nullptr;
1604 NS_HTML5_BREAK(starttagloop);
1606 default: {
1607 pop();
1608 mode = AFTER_HEAD;
1609 NS_HTML5_CONTINUE(starttagloop);
1613 inheadloop_end:;
1614 [[fallthrough]];
1616 case IN_HEAD_NOSCRIPT: {
1617 switch (group) {
1618 case HTML: {
1619 errStrayStartTag(name);
1620 if (!fragment && !isTemplateContents()) {
1621 addAttributesToHtml(attributes);
1622 attributes = nullptr;
1624 NS_HTML5_BREAK(starttagloop);
1626 case LINK_OR_BASEFONT_OR_BGSOUND: {
1627 appendVoidElementToCurrentMayFoster(elementName, attributes);
1628 selfClosing = false;
1629 attributes = nullptr;
1630 NS_HTML5_BREAK(starttagloop);
1632 case META: {
1633 checkMetaCharset(attributes);
1634 appendVoidElementToCurrentMayFoster(elementName, attributes);
1635 selfClosing = false;
1636 attributes = nullptr;
1637 NS_HTML5_BREAK(starttagloop);
1639 case STYLE:
1640 case NOFRAMES: {
1641 appendToCurrentNodeAndPushElement(elementName, attributes);
1642 originalMode = mode;
1643 mode = TEXT;
1644 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1645 elementName);
1646 attributes = nullptr;
1647 NS_HTML5_BREAK(starttagloop);
1649 case HEAD: {
1650 errFooSeenWhenFooOpen(name);
1651 NS_HTML5_BREAK(starttagloop);
1653 case NOSCRIPT: {
1654 errFooSeenWhenFooOpen(name);
1655 NS_HTML5_BREAK(starttagloop);
1657 default: {
1658 errBadStartTagInHead(name);
1659 pop();
1660 mode = IN_HEAD;
1661 continue;
1665 case IN_COLUMN_GROUP: {
1666 switch (group) {
1667 case HTML: {
1668 errStrayStartTag(name);
1669 if (!fragment && !isTemplateContents()) {
1670 addAttributesToHtml(attributes);
1671 attributes = nullptr;
1673 NS_HTML5_BREAK(starttagloop);
1675 case COL: {
1676 appendVoidElementToCurrentMayFoster(elementName, attributes);
1677 selfClosing = false;
1678 attributes = nullptr;
1679 NS_HTML5_BREAK(starttagloop);
1681 case TEMPLATE: {
1682 startTagTemplateInHead(elementName, attributes);
1683 attributes = nullptr;
1684 NS_HTML5_BREAK(starttagloop);
1686 default: {
1687 if (!currentPtr || stack[currentPtr]->getGroup() == TEMPLATE) {
1688 MOZ_ASSERT(fragment || isTemplateContents());
1689 errGarbageInColgroup();
1690 NS_HTML5_BREAK(starttagloop);
1692 pop();
1693 mode = IN_TABLE;
1694 continue;
1698 case IN_SELECT_IN_TABLE: {
1699 switch (group) {
1700 case CAPTION:
1701 case TBODY_OR_THEAD_OR_TFOOT:
1702 case TR:
1703 case TD_OR_TH:
1704 case TABLE: {
1705 errStartTagWithSelectOpen(name);
1706 eltPos = findLastInTableScope(nsGkAtoms::select);
1707 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1708 MOZ_ASSERT(fragment);
1709 NS_HTML5_BREAK(starttagloop);
1711 while (currentPtr >= eltPos) {
1712 pop();
1714 resetTheInsertionMode();
1715 continue;
1717 default:; // fall through
1719 [[fallthrough]];
1721 case IN_SELECT: {
1722 switch (group) {
1723 case HTML: {
1724 errStrayStartTag(name);
1725 if (!fragment) {
1726 addAttributesToHtml(attributes);
1727 attributes = nullptr;
1729 NS_HTML5_BREAK(starttagloop);
1731 case OPTION: {
1732 if (isCurrent(nsGkAtoms::option)) {
1733 pop();
1735 appendToCurrentNodeAndPushElement(elementName, attributes);
1736 attributes = nullptr;
1737 NS_HTML5_BREAK(starttagloop);
1739 case OPTGROUP: {
1740 if (isCurrent(nsGkAtoms::option)) {
1741 pop();
1743 if (isCurrent(nsGkAtoms::optgroup)) {
1744 pop();
1746 appendToCurrentNodeAndPushElement(elementName, attributes);
1747 attributes = nullptr;
1748 NS_HTML5_BREAK(starttagloop);
1750 case SELECT: {
1751 errStartSelectWhereEndSelectExpected();
1752 eltPos = findLastInTableScope(name);
1753 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1754 MOZ_ASSERT(fragment);
1755 errNoSelectInTableScope();
1756 NS_HTML5_BREAK(starttagloop);
1757 } else {
1758 while (currentPtr >= eltPos) {
1759 pop();
1761 resetTheInsertionMode();
1762 NS_HTML5_BREAK(starttagloop);
1765 case INPUT:
1766 case TEXTAREA: {
1767 errStartTagWithSelectOpen(name);
1768 eltPos = findLastInTableScope(nsGkAtoms::select);
1769 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1770 MOZ_ASSERT(fragment);
1771 NS_HTML5_BREAK(starttagloop);
1773 while (currentPtr >= eltPos) {
1774 pop();
1776 resetTheInsertionMode();
1777 continue;
1779 case SCRIPT: {
1780 startTagScriptInHead(elementName, attributes);
1781 attributes = nullptr;
1782 NS_HTML5_BREAK(starttagloop);
1784 case TEMPLATE: {
1785 startTagTemplateInHead(elementName, attributes);
1786 attributes = nullptr;
1787 NS_HTML5_BREAK(starttagloop);
1789 default: {
1790 errStrayStartTag(name);
1791 NS_HTML5_BREAK(starttagloop);
1795 case AFTER_BODY: {
1796 switch (group) {
1797 case HTML: {
1798 errStrayStartTag(name);
1799 if (!fragment && !isTemplateContents()) {
1800 addAttributesToHtml(attributes);
1801 attributes = nullptr;
1803 NS_HTML5_BREAK(starttagloop);
1805 default: {
1806 errStrayStartTag(name);
1807 mode = framesetOk ? FRAMESET_OK : IN_BODY;
1808 continue;
1812 case IN_FRAMESET: {
1813 switch (group) {
1814 case FRAMESET: {
1815 appendToCurrentNodeAndPushElement(elementName, attributes);
1816 attributes = nullptr;
1817 NS_HTML5_BREAK(starttagloop);
1819 case FRAME: {
1820 appendVoidElementToCurrentMayFoster(elementName, attributes);
1821 selfClosing = false;
1822 attributes = nullptr;
1823 NS_HTML5_BREAK(starttagloop);
1825 default:; // fall through
1827 [[fallthrough]];
1829 case AFTER_FRAMESET: {
1830 switch (group) {
1831 case HTML: {
1832 errStrayStartTag(name);
1833 if (!fragment && !isTemplateContents()) {
1834 addAttributesToHtml(attributes);
1835 attributes = nullptr;
1837 NS_HTML5_BREAK(starttagloop);
1839 case NOFRAMES: {
1840 appendToCurrentNodeAndPushElement(elementName, attributes);
1841 originalMode = mode;
1842 mode = TEXT;
1843 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1844 elementName);
1845 attributes = nullptr;
1846 NS_HTML5_BREAK(starttagloop);
1848 default: {
1849 errStrayStartTag(name);
1850 NS_HTML5_BREAK(starttagloop);
1854 case INITIAL: {
1855 errStartTagWithoutDoctype();
1856 documentModeInternal(QUIRKS_MODE, nullptr, nullptr, false);
1857 mode = BEFORE_HTML;
1858 continue;
1860 case BEFORE_HTML: {
1861 switch (group) {
1862 case HTML: {
1863 if (attributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
1864 appendHtmlElementToDocumentAndPush();
1865 } else {
1866 appendHtmlElementToDocumentAndPush(attributes);
1868 mode = BEFORE_HEAD;
1869 attributes = nullptr;
1870 NS_HTML5_BREAK(starttagloop);
1872 default: {
1873 appendHtmlElementToDocumentAndPush();
1874 mode = BEFORE_HEAD;
1875 continue;
1879 case BEFORE_HEAD: {
1880 switch (group) {
1881 case HTML: {
1882 errStrayStartTag(name);
1883 if (!fragment && !isTemplateContents()) {
1884 addAttributesToHtml(attributes);
1885 attributes = nullptr;
1887 NS_HTML5_BREAK(starttagloop);
1889 case HEAD: {
1890 appendToCurrentNodeAndPushHeadElement(attributes);
1891 mode = IN_HEAD;
1892 attributes = nullptr;
1893 NS_HTML5_BREAK(starttagloop);
1895 default: {
1896 appendToCurrentNodeAndPushHeadElement(
1897 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
1898 mode = IN_HEAD;
1899 continue;
1903 case AFTER_HEAD: {
1904 switch (group) {
1905 case HTML: {
1906 errStrayStartTag(name);
1907 if (!fragment && !isTemplateContents()) {
1908 addAttributesToHtml(attributes);
1909 attributes = nullptr;
1911 NS_HTML5_BREAK(starttagloop);
1913 case BODY: {
1914 if (!attributes->getLength()) {
1915 appendToCurrentNodeAndPushBodyElement();
1916 } else {
1917 appendToCurrentNodeAndPushBodyElement(attributes);
1919 framesetOk = false;
1920 mode = IN_BODY;
1921 attributes = nullptr;
1922 NS_HTML5_BREAK(starttagloop);
1924 case FRAMESET: {
1925 appendToCurrentNodeAndPushElement(elementName, attributes);
1926 mode = IN_FRAMESET;
1927 attributes = nullptr;
1928 NS_HTML5_BREAK(starttagloop);
1930 case TEMPLATE: {
1931 errFooBetweenHeadAndBody(name);
1932 pushHeadPointerOntoStack();
1933 nsHtml5StackNode* headOnStack = stack[currentPtr];
1934 startTagTemplateInHead(elementName, attributes);
1935 removeFromStack(headOnStack);
1936 attributes = nullptr;
1937 NS_HTML5_BREAK(starttagloop);
1939 case BASE:
1940 case LINK_OR_BASEFONT_OR_BGSOUND: {
1941 errFooBetweenHeadAndBody(name);
1942 pushHeadPointerOntoStack();
1943 appendVoidElementToCurrentMayFoster(elementName, attributes);
1944 selfClosing = false;
1945 pop();
1946 attributes = nullptr;
1947 NS_HTML5_BREAK(starttagloop);
1949 case META: {
1950 errFooBetweenHeadAndBody(name);
1951 checkMetaCharset(attributes);
1952 pushHeadPointerOntoStack();
1953 appendVoidElementToCurrentMayFoster(elementName, attributes);
1954 selfClosing = false;
1955 pop();
1956 attributes = nullptr;
1957 NS_HTML5_BREAK(starttagloop);
1959 case SCRIPT: {
1960 errFooBetweenHeadAndBody(name);
1961 pushHeadPointerOntoStack();
1962 appendToCurrentNodeAndPushElement(elementName, attributes);
1963 originalMode = mode;
1964 mode = TEXT;
1965 tokenizer->setStateAndEndTagExpectation(
1966 nsHtml5Tokenizer::SCRIPT_DATA, elementName);
1967 attributes = nullptr;
1968 NS_HTML5_BREAK(starttagloop);
1970 case STYLE:
1971 case NOFRAMES: {
1972 errFooBetweenHeadAndBody(name);
1973 pushHeadPointerOntoStack();
1974 appendToCurrentNodeAndPushElement(elementName, attributes);
1975 originalMode = mode;
1976 mode = TEXT;
1977 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1978 elementName);
1979 attributes = nullptr;
1980 NS_HTML5_BREAK(starttagloop);
1982 case TITLE: {
1983 errFooBetweenHeadAndBody(name);
1984 pushHeadPointerOntoStack();
1985 appendToCurrentNodeAndPushElement(elementName, attributes);
1986 originalMode = mode;
1987 mode = TEXT;
1988 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
1989 elementName);
1990 attributes = nullptr;
1991 NS_HTML5_BREAK(starttagloop);
1993 case HEAD: {
1994 errStrayStartTag(name);
1995 NS_HTML5_BREAK(starttagloop);
1997 default: {
1998 appendToCurrentNodeAndPushBodyElement();
1999 mode = FRAMESET_OK;
2000 continue;
2004 case AFTER_AFTER_BODY: {
2005 switch (group) {
2006 case HTML: {
2007 errStrayStartTag(name);
2008 if (!fragment && !isTemplateContents()) {
2009 addAttributesToHtml(attributes);
2010 attributes = nullptr;
2012 NS_HTML5_BREAK(starttagloop);
2014 default: {
2015 errStrayStartTag(name);
2017 mode = framesetOk ? FRAMESET_OK : IN_BODY;
2018 continue;
2022 case AFTER_AFTER_FRAMESET: {
2023 switch (group) {
2024 case HTML: {
2025 errStrayStartTag(name);
2026 if (!fragment && !isTemplateContents()) {
2027 addAttributesToHtml(attributes);
2028 attributes = nullptr;
2030 NS_HTML5_BREAK(starttagloop);
2032 case NOFRAMES: {
2033 startTagGenericRawText(elementName, attributes);
2034 attributes = nullptr;
2035 NS_HTML5_BREAK(starttagloop);
2037 default: {
2038 errStrayStartTag(name);
2039 NS_HTML5_BREAK(starttagloop);
2043 case TEXT: {
2044 MOZ_ASSERT(false);
2045 NS_HTML5_BREAK(starttagloop);
2049 starttagloop_end:;
2050 if (selfClosing) {
2051 errSelfClosing();
2053 if (!mBuilder && attributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
2054 delete attributes;
2058 void nsHtml5TreeBuilder::startTagTitleInHead(
2059 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2060 appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
2061 originalMode = mode;
2062 mode = TEXT;
2063 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
2064 elementName);
2067 void nsHtml5TreeBuilder::startTagGenericRawText(
2068 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2069 appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
2070 originalMode = mode;
2071 mode = TEXT;
2072 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
2073 elementName);
2076 void nsHtml5TreeBuilder::startTagScriptInHead(
2077 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2078 appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
2079 originalMode = mode;
2080 mode = TEXT;
2081 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::SCRIPT_DATA,
2082 elementName);
2085 void nsHtml5TreeBuilder::startTagTemplateInHead(
2086 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2087 appendToCurrentNodeAndPushElement(elementName, attributes);
2088 insertMarker();
2089 framesetOk = false;
2090 originalMode = mode;
2091 mode = IN_TEMPLATE;
2092 pushTemplateMode(IN_TEMPLATE);
2095 bool nsHtml5TreeBuilder::isTemplateContents() {
2096 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK !=
2097 findLast(nsGkAtoms::_template);
2100 bool nsHtml5TreeBuilder::isTemplateModeStackEmpty() {
2101 return templateModePtr == -1;
2104 bool nsHtml5TreeBuilder::isSpecialParentInForeign(nsHtml5StackNode* stackNode) {
2105 int32_t ns = stackNode->ns;
2106 return (kNameSpaceID_XHTML == ns) || (stackNode->isHtmlIntegrationPoint()) ||
2107 ((kNameSpaceID_MathML == ns) &&
2108 (stackNode->getGroup() == MI_MO_MN_MS_MTEXT));
2111 nsHtml5String nsHtml5TreeBuilder::extractCharsetFromContent(
2112 nsHtml5String attributeValue, nsHtml5TreeBuilder* tb) {
2113 int32_t charsetState = CHARSET_INITIAL;
2114 int32_t start = -1;
2115 int32_t end = -1;
2116 autoJArray<char16_t, int32_t> buffer =
2117 nsHtml5Portability::newCharArrayFromString(attributeValue);
2118 for (int32_t i = 0; i < buffer.length; i++) {
2119 char16_t c = buffer[i];
2120 switch (charsetState) {
2121 case CHARSET_INITIAL: {
2122 switch (c) {
2123 case 'c':
2124 case 'C': {
2125 charsetState = CHARSET_C;
2126 continue;
2128 default: {
2129 continue;
2133 case CHARSET_C: {
2134 switch (c) {
2135 case 'h':
2136 case 'H': {
2137 charsetState = CHARSET_H;
2138 continue;
2140 default: {
2141 charsetState = CHARSET_INITIAL;
2142 continue;
2146 case CHARSET_H: {
2147 switch (c) {
2148 case 'a':
2149 case 'A': {
2150 charsetState = CHARSET_A;
2151 continue;
2153 default: {
2154 charsetState = CHARSET_INITIAL;
2155 continue;
2159 case CHARSET_A: {
2160 switch (c) {
2161 case 'r':
2162 case 'R': {
2163 charsetState = CHARSET_R;
2164 continue;
2166 default: {
2167 charsetState = CHARSET_INITIAL;
2168 continue;
2172 case CHARSET_R: {
2173 switch (c) {
2174 case 's':
2175 case 'S': {
2176 charsetState = CHARSET_S;
2177 continue;
2179 default: {
2180 charsetState = CHARSET_INITIAL;
2181 continue;
2185 case CHARSET_S: {
2186 switch (c) {
2187 case 'e':
2188 case 'E': {
2189 charsetState = CHARSET_E;
2190 continue;
2192 default: {
2193 charsetState = CHARSET_INITIAL;
2194 continue;
2198 case CHARSET_E: {
2199 switch (c) {
2200 case 't':
2201 case 'T': {
2202 charsetState = CHARSET_T;
2203 continue;
2205 default: {
2206 charsetState = CHARSET_INITIAL;
2207 continue;
2211 case CHARSET_T: {
2212 switch (c) {
2213 case '\t':
2214 case '\n':
2215 case '\f':
2216 case '\r':
2217 case ' ': {
2218 continue;
2220 case '=': {
2221 charsetState = CHARSET_EQUALS;
2222 continue;
2224 default: {
2225 return nullptr;
2229 case CHARSET_EQUALS: {
2230 switch (c) {
2231 case '\t':
2232 case '\n':
2233 case '\f':
2234 case '\r':
2235 case ' ': {
2236 continue;
2238 case '\'': {
2239 start = i + 1;
2240 charsetState = CHARSET_SINGLE_QUOTED;
2241 continue;
2243 case '\"': {
2244 start = i + 1;
2245 charsetState = CHARSET_DOUBLE_QUOTED;
2246 continue;
2248 default: {
2249 start = i;
2250 charsetState = CHARSET_UNQUOTED;
2251 continue;
2255 case CHARSET_SINGLE_QUOTED: {
2256 switch (c) {
2257 case '\'': {
2258 end = i;
2259 NS_HTML5_BREAK(charsetloop);
2261 default: {
2262 continue;
2266 case CHARSET_DOUBLE_QUOTED: {
2267 switch (c) {
2268 case '\"': {
2269 end = i;
2270 NS_HTML5_BREAK(charsetloop);
2272 default: {
2273 continue;
2277 case CHARSET_UNQUOTED: {
2278 switch (c) {
2279 case '\t':
2280 case '\n':
2281 case '\f':
2282 case '\r':
2283 case ' ':
2284 case ';': {
2285 end = i;
2286 NS_HTML5_BREAK(charsetloop);
2288 default: {
2289 continue;
2295 charsetloop_end:;
2296 if (start != -1) {
2297 if (end == -1) {
2298 if (charsetState == CHARSET_UNQUOTED) {
2299 end = buffer.length;
2300 } else {
2301 return nullptr;
2304 return nsHtml5Portability::newStringFromBuffer(buffer, start, end - start,
2305 tb, false);
2307 return nullptr;
2310 void nsHtml5TreeBuilder::checkMetaCharset(nsHtml5HtmlAttributes* attributes) {
2311 nsHtml5String charset =
2312 attributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
2313 if (charset) {
2314 if (tokenizer->internalEncodingDeclaration(charset)) {
2315 requestSuspension();
2316 return;
2318 return;
2320 if (!nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
2321 "content-type",
2322 attributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) {
2323 return;
2325 nsHtml5String content =
2326 attributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
2327 if (content) {
2328 nsHtml5String extract =
2329 nsHtml5TreeBuilder::extractCharsetFromContent(content, this);
2330 if (extract) {
2331 if (tokenizer->internalEncodingDeclaration(extract)) {
2332 requestSuspension();
2335 extract.Release();
2339 void nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) {
2340 flushCharacters();
2341 needToDropLF = false;
2342 int32_t eltPos;
2343 int32_t group = elementName->getGroup();
2344 nsAtom* name = elementName->getName();
2345 for (;;) {
2346 if (isInForeign()) {
2347 if (stack[currentPtr]->name != name) {
2348 if (!currentPtr) {
2349 errStrayEndTag(name);
2350 } else {
2351 errEndTagDidNotMatchCurrentOpenElement(name,
2352 stack[currentPtr]->popName);
2355 eltPos = currentPtr;
2356 int32_t origPos = currentPtr;
2357 for (;;) {
2358 if (!eltPos) {
2359 MOZ_ASSERT(fragment,
2360 "We can get this close to the root of the stack in "
2361 "foreign content only in the fragment case.");
2362 NS_HTML5_BREAK(endtagloop);
2364 if (stack[eltPos]->name == name) {
2365 while (currentPtr >= eltPos) {
2366 popForeign(origPos, eltPos);
2368 NS_HTML5_BREAK(endtagloop);
2370 if (stack[--eltPos]->ns == kNameSpaceID_XHTML) {
2371 break;
2375 switch (mode) {
2376 case IN_TEMPLATE: {
2377 switch (group) {
2378 case TEMPLATE: {
2379 break;
2381 default: {
2382 errStrayEndTag(name);
2383 NS_HTML5_BREAK(endtagloop);
2386 [[fallthrough]];
2388 case IN_ROW: {
2389 switch (group) {
2390 case TR: {
2391 eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
2392 if (!eltPos) {
2393 MOZ_ASSERT(fragment || isTemplateContents());
2394 errNoTableRowToClose();
2395 NS_HTML5_BREAK(endtagloop);
2397 clearStackBackTo(eltPos);
2398 pop();
2399 mode = IN_TABLE_BODY;
2400 NS_HTML5_BREAK(endtagloop);
2402 case TABLE: {
2403 eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
2404 if (!eltPos) {
2405 MOZ_ASSERT(fragment || isTemplateContents());
2406 errNoTableRowToClose();
2407 NS_HTML5_BREAK(endtagloop);
2409 clearStackBackTo(eltPos);
2410 pop();
2411 mode = IN_TABLE_BODY;
2412 continue;
2414 case TBODY_OR_THEAD_OR_TFOOT: {
2415 if (findLastInTableScope(name) ==
2416 nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2417 errStrayEndTag(name);
2418 NS_HTML5_BREAK(endtagloop);
2420 eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
2421 if (!eltPos) {
2422 MOZ_ASSERT(fragment || isTemplateContents());
2423 errNoTableRowToClose();
2424 NS_HTML5_BREAK(endtagloop);
2426 clearStackBackTo(eltPos);
2427 pop();
2428 mode = IN_TABLE_BODY;
2429 continue;
2431 case BODY:
2432 case CAPTION:
2433 case COL:
2434 case COLGROUP:
2435 case HTML:
2436 case TD_OR_TH: {
2437 errStrayEndTag(name);
2438 NS_HTML5_BREAK(endtagloop);
2440 default:; // fall through
2442 [[fallthrough]];
2444 case IN_TABLE_BODY: {
2445 switch (group) {
2446 case TBODY_OR_THEAD_OR_TFOOT: {
2447 eltPos = findLastOrRoot(name);
2448 if (!eltPos) {
2449 errStrayEndTag(name);
2450 NS_HTML5_BREAK(endtagloop);
2452 clearStackBackTo(eltPos);
2453 pop();
2454 mode = IN_TABLE;
2455 NS_HTML5_BREAK(endtagloop);
2457 case TABLE: {
2458 eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
2459 if (!eltPos || stack[eltPos]->getGroup() == TEMPLATE) {
2460 MOZ_ASSERT(fragment || isTemplateContents());
2461 errStrayEndTag(name);
2462 NS_HTML5_BREAK(endtagloop);
2464 clearStackBackTo(eltPos);
2465 pop();
2466 mode = IN_TABLE;
2467 continue;
2469 case BODY:
2470 case CAPTION:
2471 case COL:
2472 case COLGROUP:
2473 case HTML:
2474 case TD_OR_TH:
2475 case TR: {
2476 errStrayEndTag(name);
2477 NS_HTML5_BREAK(endtagloop);
2479 default:; // fall through
2481 [[fallthrough]];
2483 case IN_TABLE: {
2484 switch (group) {
2485 case TABLE: {
2486 eltPos = findLast(nsGkAtoms::table);
2487 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2488 MOZ_ASSERT(fragment || isTemplateContents());
2489 errStrayEndTag(name);
2490 NS_HTML5_BREAK(endtagloop);
2492 while (currentPtr >= eltPos) {
2493 pop();
2495 resetTheInsertionMode();
2496 NS_HTML5_BREAK(endtagloop);
2498 case BODY:
2499 case CAPTION:
2500 case COL:
2501 case COLGROUP:
2502 case HTML:
2503 case TBODY_OR_THEAD_OR_TFOOT:
2504 case TD_OR_TH:
2505 case TR: {
2506 errStrayEndTag(name);
2507 NS_HTML5_BREAK(endtagloop);
2509 case TEMPLATE: {
2510 break;
2512 default: {
2513 errStrayEndTag(name);
2516 [[fallthrough]];
2518 case IN_CAPTION: {
2519 switch (group) {
2520 case CAPTION: {
2521 eltPos = findLastInTableScope(nsGkAtoms::caption);
2522 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2523 NS_HTML5_BREAK(endtagloop);
2525 generateImpliedEndTags();
2526 if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
2527 errUnclosedElements(eltPos, name);
2529 while (currentPtr >= eltPos) {
2530 pop();
2532 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
2533 mode = IN_TABLE;
2534 NS_HTML5_BREAK(endtagloop);
2536 case TABLE: {
2537 errTableClosedWhileCaptionOpen();
2538 eltPos = findLastInTableScope(nsGkAtoms::caption);
2539 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
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, false);
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(
3337 nsHtml5DocumentMode m, nsHtml5String publicIdentifier,
3338 nsHtml5String systemIdentifier, bool html4SpecificAdditionalErrorChecks) {
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"