Backed out changeset 6a14206eb5a9 (bug 1299271) for causing python taskgraph-tests...
[gecko.git] / parser / html / nsHtml5TreeBuilder.cpp
blobf28d6441e227952307f94c06bff8492dbf07030c
1 /*
2 * Copyright (c) 2007 Henri Sivonen
3 * Copyright (c) 2007-2017 Mozilla Foundation
4 * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla
5 * Foundation, and Opera Software ASA.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
27 * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
28 * Please edit TreeBuilder.java instead and regenerate.
31 #define nsHtml5TreeBuilder_cpp__
33 #include "nsHtml5AttributeName.h"
34 #include "nsHtml5ElementName.h"
35 #include "nsHtml5Tokenizer.h"
36 #include "nsHtml5StackNode.h"
37 #include "nsHtml5UTF16Buffer.h"
38 #include "nsHtml5StateSnapshot.h"
39 #include "nsHtml5Portability.h"
41 #include "nsHtml5TreeBuilder.h"
43 char16_t nsHtml5TreeBuilder::REPLACEMENT_CHARACTER[] = {0xfffd};
44 static const char* const QUIRKY_PUBLIC_IDS_DATA[] = {
45 "+//silmaril//dtd html pro v0r11 19970101//",
46 "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
47 "-//as//dtd html 3.0 aswedit + extensions//",
48 "-//ietf//dtd html 2.0 level 1//",
49 "-//ietf//dtd html 2.0 level 2//",
50 "-//ietf//dtd html 2.0 strict level 1//",
51 "-//ietf//dtd html 2.0 strict level 2//",
52 "-//ietf//dtd html 2.0 strict//",
53 "-//ietf//dtd html 2.0//",
54 "-//ietf//dtd html 2.1e//",
55 "-//ietf//dtd html 3.0//",
56 "-//ietf//dtd html 3.2 final//",
57 "-//ietf//dtd html 3.2//",
58 "-//ietf//dtd html 3//",
59 "-//ietf//dtd html level 0//",
60 "-//ietf//dtd html level 1//",
61 "-//ietf//dtd html level 2//",
62 "-//ietf//dtd html level 3//",
63 "-//ietf//dtd html strict level 0//",
64 "-//ietf//dtd html strict level 1//",
65 "-//ietf//dtd html strict level 2//",
66 "-//ietf//dtd html strict level 3//",
67 "-//ietf//dtd html strict//",
68 "-//ietf//dtd html//",
69 "-//metrius//dtd metrius presentational//",
70 "-//microsoft//dtd internet explorer 2.0 html strict//",
71 "-//microsoft//dtd internet explorer 2.0 html//",
72 "-//microsoft//dtd internet explorer 2.0 tables//",
73 "-//microsoft//dtd internet explorer 3.0 html strict//",
74 "-//microsoft//dtd internet explorer 3.0 html//",
75 "-//microsoft//dtd internet explorer 3.0 tables//",
76 "-//netscape comm. corp.//dtd html//",
77 "-//netscape comm. corp.//dtd strict html//",
78 "-//o'reilly and associates//dtd html 2.0//",
79 "-//o'reilly and associates//dtd html extended 1.0//",
80 "-//o'reilly and associates//dtd html extended relaxed 1.0//",
81 "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html "
82 "4.0//",
83 "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
84 "-//spyglass//dtd html 2.0 extended//",
85 "-//sq//dtd html 2.0 hotmetal + extensions//",
86 "-//sun microsystems corp.//dtd hotjava html//",
87 "-//sun microsystems corp.//dtd hotjava strict html//",
88 "-//w3c//dtd html 3 1995-03-24//",
89 "-//w3c//dtd html 3.2 draft//",
90 "-//w3c//dtd html 3.2 final//",
91 "-//w3c//dtd html 3.2//",
92 "-//w3c//dtd html 3.2s draft//",
93 "-//w3c//dtd html 4.0 frameset//",
94 "-//w3c//dtd html 4.0 transitional//",
95 "-//w3c//dtd html experimental 19960712//",
96 "-//w3c//dtd html experimental 970421//",
97 "-//w3c//dtd w3 html//",
98 "-//w3o//dtd w3 html 3.0//",
99 "-//webtechs//dtd mozilla html 2.0//",
100 "-//webtechs//dtd mozilla html//"};
101 staticJArray<const char*, int32_t> nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS = {
102 QUIRKY_PUBLIC_IDS_DATA, MOZ_ARRAY_LENGTH(QUIRKY_PUBLIC_IDS_DATA)};
103 void nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self) {
104 tokenizer = self;
105 stackNodes = jArray<nsHtml5StackNode*, int32_t>::newJArray(64);
106 stack = jArray<nsHtml5StackNode*, int32_t>::newJArray(64);
107 templateModeStack = jArray<int32_t, int32_t>::newJArray(64);
108 listOfActiveFormattingElements =
109 jArray<nsHtml5StackNode*, int32_t>::newJArray(64);
110 needToDropLF = false;
111 originalMode = INITIAL;
112 templateModePtr = -1;
113 stackNodesIdx = 0;
114 numStackNodes = 0;
115 currentPtr = -1;
116 listPtr = -1;
117 formPointer = nullptr;
118 headPointer = nullptr;
119 start(fragment);
120 charBufferLen = 0;
121 charBuffer = nullptr;
122 framesetOk = true;
123 if (fragment) {
124 nsIContentHandle* elt;
125 if (contextNode) {
126 elt = contextNode;
127 } else {
128 elt = createHtmlElementSetAsRoot(tokenizer->emptyAttributes());
130 if (contextNamespace == kNameSpaceID_SVG) {
131 nsHtml5ElementName* elementName = nsHtml5ElementName::ELT_SVG;
132 if (nsGkAtoms::title == contextName || nsGkAtoms::desc == contextName ||
133 nsGkAtoms::foreignObject == contextName) {
134 elementName = nsHtml5ElementName::ELT_FOREIGNOBJECT;
136 nsHtml5StackNode* node =
137 createStackNode(elementName, elementName->getCamelCaseName(), elt);
138 currentPtr++;
139 stack[currentPtr] = node;
140 tokenizer->setState(nsHtml5Tokenizer::DATA);
141 mode = FRAMESET_OK;
142 } else if (contextNamespace == kNameSpaceID_MathML) {
143 nsHtml5ElementName* elementName = nsHtml5ElementName::ELT_MATH;
144 if (nsGkAtoms::mi_ == contextName || nsGkAtoms::mo_ == contextName ||
145 nsGkAtoms::mn_ == contextName || nsGkAtoms::ms_ == contextName ||
146 nsGkAtoms::mtext_ == contextName) {
147 elementName = nsHtml5ElementName::ELT_MTEXT;
148 } else if (nsGkAtoms::annotation_xml_ == contextName) {
149 elementName = nsHtml5ElementName::ELT_ANNOTATION_XML;
151 nsHtml5StackNode* node =
152 createStackNode(elementName, elt, elementName->getName(), false);
153 currentPtr++;
154 stack[currentPtr] = node;
155 tokenizer->setState(nsHtml5Tokenizer::DATA);
156 mode = FRAMESET_OK;
157 } else {
158 nsHtml5StackNode* node =
159 createStackNode(nsHtml5ElementName::ELT_HTML, elt);
160 currentPtr++;
161 stack[currentPtr] = node;
162 if (nsGkAtoms::_template == contextName) {
163 pushTemplateMode(IN_TEMPLATE);
165 resetTheInsertionMode();
166 formPointer = getFormPointerForContext(contextNode);
167 if (nsGkAtoms::title == contextName ||
168 nsGkAtoms::textarea == contextName) {
169 tokenizer->setState(nsHtml5Tokenizer::RCDATA);
170 } else if (nsGkAtoms::style == contextName ||
171 nsGkAtoms::xmp == contextName ||
172 nsGkAtoms::iframe == contextName ||
173 nsGkAtoms::noembed == contextName ||
174 nsGkAtoms::noframes == contextName ||
175 (scriptingEnabled && nsGkAtoms::noscript == contextName)) {
176 tokenizer->setState(nsHtml5Tokenizer::RAWTEXT);
177 } else if (nsGkAtoms::plaintext == contextName) {
178 tokenizer->setState(nsHtml5Tokenizer::PLAINTEXT);
179 } else if (nsGkAtoms::script == contextName) {
180 tokenizer->setState(nsHtml5Tokenizer::SCRIPT_DATA);
181 } else {
182 tokenizer->setState(nsHtml5Tokenizer::DATA);
185 } else {
186 mode = INITIAL;
187 if (tokenizer->isViewingXmlSource()) {
188 nsIContentHandle* elt = createElement(
189 kNameSpaceID_SVG, nsGkAtoms::svg, tokenizer->emptyAttributes(),
190 nullptr, svgCreator(NS_NewSVGSVGElement));
191 nsHtml5StackNode* node =
192 createStackNode(nsHtml5ElementName::ELT_SVG, nsGkAtoms::svg, elt);
193 currentPtr++;
194 stack[currentPtr] = node;
199 void nsHtml5TreeBuilder::doctype(nsAtom* name, nsHtml5String publicIdentifier,
200 nsHtml5String systemIdentifier,
201 bool forceQuirks) {
202 needToDropLF = false;
203 if (!isInForeign() && mode == INITIAL) {
204 nsHtml5String emptyString = nsHtml5Portability::newEmptyString();
205 appendDoctypeToDocument(!name ? nsGkAtoms::_empty : name,
206 !publicIdentifier ? emptyString : publicIdentifier,
207 !systemIdentifier ? emptyString : systemIdentifier);
208 emptyString.Release();
209 if (isQuirky(name, publicIdentifier, systemIdentifier, forceQuirks)) {
210 errQuirkyDoctype();
211 documentModeInternal(QUIRKS_MODE, publicIdentifier, systemIdentifier);
212 } else if (isAlmostStandards(publicIdentifier, systemIdentifier)) {
213 errAlmostStandardsDoctype();
214 documentModeInternal(ALMOST_STANDARDS_MODE, publicIdentifier,
215 systemIdentifier);
216 } else {
217 documentModeInternal(STANDARDS_MODE, publicIdentifier, systemIdentifier);
219 mode = BEFORE_HTML;
220 return;
222 errStrayDoctype();
223 return;
226 void nsHtml5TreeBuilder::comment(char16_t* buf, int32_t start, int32_t length) {
227 needToDropLF = false;
228 if (!isInForeign()) {
229 switch (mode) {
230 case INITIAL:
231 case BEFORE_HTML:
232 case AFTER_AFTER_BODY:
233 case AFTER_AFTER_FRAMESET: {
234 appendCommentToDocument(buf, start, length);
235 return;
237 case AFTER_BODY: {
238 flushCharacters();
239 appendComment(stack[0]->node, buf, start, length);
240 return;
242 default: {
243 break;
247 flushCharacters();
248 appendComment(stack[currentPtr]->node, buf, start, length);
249 return;
252 void nsHtml5TreeBuilder::characters(const char16_t* buf, int32_t start,
253 int32_t length) {
254 if (tokenizer->isViewingXmlSource()) {
255 return;
257 if (needToDropLF) {
258 needToDropLF = false;
259 if (buf[start] == '\n') {
260 start++;
261 length--;
262 if (!length) {
263 return;
267 switch (mode) {
268 case IN_BODY:
269 case IN_CELL:
270 case IN_CAPTION: {
271 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
272 reconstructTheActiveFormattingElements();
274 [[fallthrough]];
276 case TEXT: {
277 accumulateCharacters(buf, start, length);
278 return;
280 case IN_TABLE:
281 case IN_TABLE_BODY:
282 case IN_ROW: {
283 accumulateCharactersForced(buf, start, length);
284 return;
286 default: {
287 int32_t end = start + length;
288 for (int32_t i = start; i < end; i++) {
289 switch (buf[i]) {
290 case ' ':
291 case '\t':
292 case '\n':
293 case '\r':
294 case '\f': {
295 switch (mode) {
296 case INITIAL:
297 case BEFORE_HTML:
298 case BEFORE_HEAD: {
299 start = i + 1;
300 continue;
302 case IN_HEAD:
303 case IN_HEAD_NOSCRIPT:
304 case AFTER_HEAD:
305 case IN_COLUMN_GROUP:
306 case IN_FRAMESET:
307 case AFTER_FRAMESET: {
308 continue;
310 case FRAMESET_OK:
311 case IN_TEMPLATE:
312 case IN_BODY:
313 case IN_CELL:
314 case IN_CAPTION: {
315 if (start < i) {
316 accumulateCharacters(buf, start, i - start);
317 start = i;
319 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
320 flushCharacters();
321 reconstructTheActiveFormattingElements();
323 NS_HTML5_BREAK(charactersloop);
325 case IN_SELECT:
326 case IN_SELECT_IN_TABLE: {
327 NS_HTML5_BREAK(charactersloop);
329 case IN_TABLE:
330 case IN_TABLE_BODY:
331 case IN_ROW: {
332 accumulateCharactersForced(buf, i, 1);
333 start = i + 1;
334 continue;
336 case AFTER_BODY:
337 case AFTER_AFTER_BODY:
338 case AFTER_AFTER_FRAMESET: {
339 if (start < i) {
340 accumulateCharacters(buf, start, i - start);
341 start = i;
343 flushCharacters();
344 reconstructTheActiveFormattingElements();
345 continue;
348 MOZ_FALLTHROUGH_ASSERT();
350 default: {
351 switch (mode) {
352 case INITIAL: {
353 documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
354 mode = BEFORE_HTML;
355 i--;
356 continue;
358 case BEFORE_HTML: {
359 appendHtmlElementToDocumentAndPush();
360 mode = BEFORE_HEAD;
361 i--;
362 continue;
364 case BEFORE_HEAD: {
365 if (start < i) {
366 accumulateCharacters(buf, start, i - start);
367 start = i;
369 flushCharacters();
370 appendToCurrentNodeAndPushHeadElement(
371 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
372 mode = IN_HEAD;
373 i--;
374 continue;
376 case IN_HEAD: {
377 if (start < i) {
378 accumulateCharacters(buf, start, i - start);
379 start = i;
381 flushCharacters();
382 pop();
383 mode = AFTER_HEAD;
384 i--;
385 continue;
387 case IN_HEAD_NOSCRIPT: {
388 if (start < i) {
389 accumulateCharacters(buf, start, i - start);
390 start = i;
392 errNonSpaceInNoscriptInHead();
393 flushCharacters();
394 pop();
395 mode = IN_HEAD;
396 i--;
397 continue;
399 case AFTER_HEAD: {
400 if (start < i) {
401 accumulateCharacters(buf, start, i - start);
402 start = i;
404 flushCharacters();
405 appendToCurrentNodeAndPushBodyElement();
406 mode = FRAMESET_OK;
407 i--;
408 continue;
410 case FRAMESET_OK: {
411 framesetOk = false;
412 mode = IN_BODY;
413 i--;
414 continue;
416 case IN_TEMPLATE:
417 case IN_BODY:
418 case IN_CELL:
419 case IN_CAPTION: {
420 if (start < i) {
421 accumulateCharacters(buf, start, i - start);
422 start = i;
424 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
425 flushCharacters();
426 reconstructTheActiveFormattingElements();
428 NS_HTML5_BREAK(charactersloop);
430 case IN_TABLE:
431 case IN_TABLE_BODY:
432 case IN_ROW: {
433 accumulateCharactersForced(buf, i, 1);
434 start = i + 1;
435 continue;
437 case IN_COLUMN_GROUP: {
438 if (start < i) {
439 accumulateCharacters(buf, start, i - start);
440 start = i;
442 if (!currentPtr || stack[currentPtr]->getGroup() ==
443 nsHtml5TreeBuilder::TEMPLATE) {
444 errNonSpaceInColgroupInFragment();
445 start = i + 1;
446 continue;
448 flushCharacters();
449 pop();
450 mode = IN_TABLE;
451 i--;
452 continue;
454 case IN_SELECT:
455 case IN_SELECT_IN_TABLE: {
456 NS_HTML5_BREAK(charactersloop);
458 case AFTER_BODY: {
459 errNonSpaceAfterBody();
461 mode = framesetOk ? FRAMESET_OK : IN_BODY;
462 i--;
463 continue;
465 case IN_FRAMESET: {
466 if (start < i) {
467 accumulateCharacters(buf, start, i - start);
469 errNonSpaceInFrameset();
470 start = i + 1;
471 continue;
473 case AFTER_FRAMESET: {
474 if (start < i) {
475 accumulateCharacters(buf, start, i - start);
477 errNonSpaceAfterFrameset();
478 start = i + 1;
479 continue;
481 case AFTER_AFTER_BODY: {
482 errNonSpaceInTrailer();
483 mode = framesetOk ? FRAMESET_OK : IN_BODY;
484 i--;
485 continue;
487 case AFTER_AFTER_FRAMESET: {
488 if (start < i) {
489 accumulateCharacters(buf, start, i - start);
491 errNonSpaceInTrailer();
492 start = i + 1;
493 continue;
499 charactersloop_end:;
500 if (start < end) {
501 accumulateCharacters(buf, start, end - start);
507 void nsHtml5TreeBuilder::zeroOriginatingReplacementCharacter() {
508 if (mode == TEXT) {
509 accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1);
510 return;
512 if (currentPtr >= 0) {
513 if (isSpecialParentInForeign(stack[currentPtr])) {
514 return;
516 accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1);
520 void nsHtml5TreeBuilder::zeroOrReplacementCharacter() {
521 zeroOriginatingReplacementCharacter();
524 void nsHtml5TreeBuilder::eof() {
525 flushCharacters();
526 for (;;) {
527 switch (mode) {
528 case INITIAL: {
529 documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
530 mode = BEFORE_HTML;
531 continue;
533 case BEFORE_HTML: {
534 appendHtmlElementToDocumentAndPush();
535 mode = BEFORE_HEAD;
536 continue;
538 case BEFORE_HEAD: {
539 appendToCurrentNodeAndPushHeadElement(
540 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
541 mode = IN_HEAD;
542 continue;
544 case IN_HEAD: {
545 while (currentPtr > 0) {
546 popOnEof();
548 mode = AFTER_HEAD;
549 continue;
551 case IN_HEAD_NOSCRIPT: {
552 while (currentPtr > 1) {
553 popOnEof();
555 mode = IN_HEAD;
556 continue;
558 case AFTER_HEAD: {
559 appendToCurrentNodeAndPushBodyElement();
560 mode = IN_BODY;
561 continue;
563 case IN_TABLE_BODY:
564 case IN_ROW:
565 case IN_TABLE:
566 case IN_SELECT_IN_TABLE:
567 case IN_SELECT:
568 case IN_COLUMN_GROUP:
569 case FRAMESET_OK:
570 case IN_CAPTION:
571 case IN_CELL:
572 case IN_BODY: {
573 if (isTemplateModeStackEmpty()) {
574 NS_HTML5_BREAK(eofloop);
576 [[fallthrough]];
578 case IN_TEMPLATE: {
579 int32_t eltPos = findLast(nsGkAtoms::_template);
580 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
581 MOZ_ASSERT(fragment);
582 NS_HTML5_BREAK(eofloop);
584 if (MOZ_UNLIKELY(mViewSource)) {
585 errListUnclosedStartTags(0);
587 while (currentPtr >= eltPos) {
588 pop();
590 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
591 popTemplateMode();
592 resetTheInsertionMode();
593 continue;
595 case TEXT: {
596 if (originalMode == AFTER_HEAD) {
597 popOnEof();
599 popOnEof();
600 mode = originalMode;
601 continue;
603 case IN_FRAMESET: {
604 NS_HTML5_BREAK(eofloop);
606 case AFTER_BODY:
607 case AFTER_FRAMESET:
608 case AFTER_AFTER_BODY:
609 case AFTER_AFTER_FRAMESET:
610 default: {
611 NS_HTML5_BREAK(eofloop);
615 eofloop_end:;
616 while (currentPtr > 0) {
617 popOnEof();
619 if (!fragment) {
620 popOnEof();
624 void nsHtml5TreeBuilder::endTokenization() {
625 formPointer = nullptr;
626 headPointer = nullptr;
627 contextName = nullptr;
628 contextNode = nullptr;
629 templateModeStack = nullptr;
630 if (stack) {
631 while (currentPtr > -1) {
632 stack[currentPtr]->release(this);
633 currentPtr--;
635 stack = nullptr;
637 if (listOfActiveFormattingElements) {
638 while (listPtr > -1) {
639 if (listOfActiveFormattingElements[listPtr]) {
640 listOfActiveFormattingElements[listPtr]->release(this);
642 listPtr--;
644 listOfActiveFormattingElements = nullptr;
646 if (stackNodes) {
647 for (int32_t i = 0; i < numStackNodes; i++) {
648 MOZ_ASSERT(stackNodes[i]->isUnused());
649 delete stackNodes[i];
651 numStackNodes = 0;
652 stackNodesIdx = 0;
653 stackNodes = nullptr;
655 charBuffer = nullptr;
656 end();
659 void nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName,
660 nsHtml5HtmlAttributes* attributes,
661 bool selfClosing) {
662 flushCharacters();
663 int32_t eltPos;
664 needToDropLF = false;
665 starttagloop:
666 for (;;) {
667 int32_t group = elementName->getGroup();
668 nsAtom* name = elementName->getName();
669 if (isInForeign()) {
670 nsHtml5StackNode* currentNode = stack[currentPtr];
671 int32_t currNs = currentNode->ns;
672 if (!(currentNode->isHtmlIntegrationPoint() ||
673 (currNs == kNameSpaceID_MathML &&
674 ((currentNode->getGroup() == MI_MO_MN_MS_MTEXT &&
675 group != MGLYPH_OR_MALIGNMARK) ||
676 (currentNode->getGroup() == ANNOTATION_XML && group == SVG))))) {
677 switch (group) {
678 case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
679 case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
680 case BODY:
681 case BR:
682 case RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR:
683 case DD_OR_DT:
684 case UL_OR_OL_OR_DL:
685 case EMBED:
686 case IMG:
687 case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6:
688 case HEAD:
689 case HR:
690 case LI:
691 case META:
692 case NOBR:
693 case P:
694 case PRE_OR_LISTING:
695 case TABLE:
696 case FONT: {
697 if (!(group == FONT &&
698 !(attributes->contains(nsHtml5AttributeName::ATTR_COLOR) ||
699 attributes->contains(nsHtml5AttributeName::ATTR_FACE) ||
700 attributes->contains(nsHtml5AttributeName::ATTR_SIZE)))) {
701 errHtmlStartTagInForeignContext(name);
702 if (!fragment) {
703 while (!isSpecialParentInForeign(stack[currentPtr])) {
704 popForeign(-1, -1);
706 NS_HTML5_CONTINUE(starttagloop);
709 [[fallthrough]];
711 default: {
712 if (kNameSpaceID_SVG == currNs) {
713 attributes->adjustForSvg();
714 if (selfClosing) {
715 appendVoidElementToCurrentMayFosterSVG(elementName, attributes);
716 selfClosing = false;
717 } else {
718 appendToCurrentNodeAndPushElementMayFosterSVG(elementName,
719 attributes);
721 attributes = nullptr;
722 NS_HTML5_BREAK(starttagloop);
723 } else {
724 attributes->adjustForMath();
725 if (selfClosing) {
726 appendVoidElementToCurrentMayFosterMathML(elementName,
727 attributes);
728 selfClosing = false;
729 } else {
730 appendToCurrentNodeAndPushElementMayFosterMathML(elementName,
731 attributes);
733 attributes = nullptr;
734 NS_HTML5_BREAK(starttagloop);
740 switch (mode) {
741 case IN_TEMPLATE: {
742 switch (group) {
743 case COL: {
744 popTemplateMode();
745 pushTemplateMode(IN_COLUMN_GROUP);
746 mode = IN_COLUMN_GROUP;
747 continue;
749 case CAPTION:
750 case COLGROUP:
751 case TBODY_OR_THEAD_OR_TFOOT: {
752 popTemplateMode();
753 pushTemplateMode(IN_TABLE);
754 mode = IN_TABLE;
755 continue;
757 case TR: {
758 popTemplateMode();
759 pushTemplateMode(IN_TABLE_BODY);
760 mode = IN_TABLE_BODY;
761 continue;
763 case TD_OR_TH: {
764 popTemplateMode();
765 pushTemplateMode(IN_ROW);
766 mode = IN_ROW;
767 continue;
769 case META: {
770 checkMetaCharset(attributes);
771 appendVoidElementToCurrentMayFoster(elementName, attributes);
772 selfClosing = false;
773 attributes = nullptr;
774 NS_HTML5_BREAK(starttagloop);
776 case TITLE: {
777 startTagTitleInHead(elementName, attributes);
778 attributes = nullptr;
779 NS_HTML5_BREAK(starttagloop);
781 case BASE:
782 case LINK_OR_BASEFONT_OR_BGSOUND: {
783 appendVoidElementToCurrentMayFoster(elementName, attributes);
784 selfClosing = false;
785 attributes = nullptr;
786 NS_HTML5_BREAK(starttagloop);
788 case SCRIPT: {
789 startTagScriptInHead(elementName, attributes);
790 attributes = nullptr;
791 NS_HTML5_BREAK(starttagloop);
793 case NOFRAMES:
794 case STYLE: {
795 startTagGenericRawText(elementName, attributes);
796 attributes = nullptr;
797 NS_HTML5_BREAK(starttagloop);
799 case TEMPLATE: {
800 startTagTemplateInHead(elementName, attributes);
801 attributes = nullptr;
802 NS_HTML5_BREAK(starttagloop);
804 default: {
805 popTemplateMode();
806 pushTemplateMode(IN_BODY);
807 mode = IN_BODY;
808 continue;
812 case IN_ROW: {
813 switch (group) {
814 case TD_OR_TH: {
815 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TR));
816 appendToCurrentNodeAndPushElement(elementName, attributes);
817 mode = IN_CELL;
818 insertMarker();
819 attributes = nullptr;
820 NS_HTML5_BREAK(starttagloop);
822 case CAPTION:
823 case COL:
824 case COLGROUP:
825 case TBODY_OR_THEAD_OR_TFOOT:
826 case TR: {
827 eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
828 if (!eltPos) {
829 MOZ_ASSERT(fragment || isTemplateContents());
830 errNoTableRowToClose();
831 NS_HTML5_BREAK(starttagloop);
833 clearStackBackTo(eltPos);
834 pop();
835 mode = IN_TABLE_BODY;
836 continue;
838 default:; // fall through
840 [[fallthrough]];
842 case IN_TABLE_BODY: {
843 switch (group) {
844 case TR: {
845 clearStackBackTo(
846 findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
847 appendToCurrentNodeAndPushElement(elementName, attributes);
848 mode = IN_ROW;
849 attributes = nullptr;
850 NS_HTML5_BREAK(starttagloop);
852 case TD_OR_TH: {
853 errStartTagInTableBody(name);
854 clearStackBackTo(
855 findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
856 appendToCurrentNodeAndPushElement(
857 nsHtml5ElementName::ELT_TR,
858 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
859 mode = IN_ROW;
860 continue;
862 case CAPTION:
863 case COL:
864 case COLGROUP:
865 case TBODY_OR_THEAD_OR_TFOOT: {
866 eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
867 if (!eltPos || stack[eltPos]->getGroup() == TEMPLATE) {
868 MOZ_ASSERT(fragment || isTemplateContents());
869 errStrayStartTag(name);
870 NS_HTML5_BREAK(starttagloop);
871 } else {
872 clearStackBackTo(eltPos);
873 pop();
874 mode = IN_TABLE;
875 continue;
878 default:; // fall through
880 [[fallthrough]];
882 case IN_TABLE: {
883 for (;;) {
884 switch (group) {
885 case CAPTION: {
886 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
887 insertMarker();
888 appendToCurrentNodeAndPushElement(elementName, attributes);
889 mode = IN_CAPTION;
890 attributes = nullptr;
891 NS_HTML5_BREAK(starttagloop);
893 case COLGROUP: {
894 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
895 appendToCurrentNodeAndPushElement(elementName, attributes);
896 mode = IN_COLUMN_GROUP;
897 attributes = nullptr;
898 NS_HTML5_BREAK(starttagloop);
900 case COL: {
901 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
902 appendToCurrentNodeAndPushElement(
903 nsHtml5ElementName::ELT_COLGROUP,
904 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
905 mode = IN_COLUMN_GROUP;
906 NS_HTML5_CONTINUE(starttagloop);
908 case TBODY_OR_THEAD_OR_TFOOT: {
909 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
910 appendToCurrentNodeAndPushElement(elementName, attributes);
911 mode = IN_TABLE_BODY;
912 attributes = nullptr;
913 NS_HTML5_BREAK(starttagloop);
915 case TR:
916 case TD_OR_TH: {
917 clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
918 appendToCurrentNodeAndPushElement(
919 nsHtml5ElementName::ELT_TBODY,
920 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
921 mode = IN_TABLE_BODY;
922 NS_HTML5_CONTINUE(starttagloop);
924 case TEMPLATE: {
925 NS_HTML5_BREAK(intableloop);
927 case TABLE: {
928 errTableSeenWhileTableOpen();
929 eltPos = findLastInTableScope(name);
930 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
931 MOZ_ASSERT(fragment || isTemplateContents());
932 NS_HTML5_BREAK(starttagloop);
934 generateImpliedEndTags();
935 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(nsGkAtoms::table)) {
936 errNoCheckUnclosedElementsOnStack();
938 while (currentPtr >= eltPos) {
939 pop();
941 resetTheInsertionMode();
942 NS_HTML5_CONTINUE(starttagloop);
944 case SCRIPT: {
945 appendToCurrentNodeAndPushElement(elementName, attributes);
946 originalMode = mode;
947 mode = TEXT;
948 tokenizer->setStateAndEndTagExpectation(
949 nsHtml5Tokenizer::SCRIPT_DATA, elementName);
950 attributes = nullptr;
951 NS_HTML5_BREAK(starttagloop);
953 case STYLE: {
954 appendToCurrentNodeAndPushElement(elementName, attributes);
955 originalMode = mode;
956 mode = TEXT;
957 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
958 elementName);
959 attributes = nullptr;
960 NS_HTML5_BREAK(starttagloop);
962 case INPUT: {
963 errStartTagInTable(name);
964 if (!nsHtml5Portability::
965 lowerCaseLiteralEqualsIgnoreAsciiCaseString(
966 "hidden", attributes->getValue(
967 nsHtml5AttributeName::ATTR_TYPE))) {
968 NS_HTML5_BREAK(intableloop);
970 appendVoidInputToCurrent(attributes, formPointer);
971 selfClosing = false;
972 attributes = nullptr;
973 NS_HTML5_BREAK(starttagloop);
975 case FORM: {
976 if (!!formPointer || isTemplateContents()) {
977 errFormWhenFormOpen();
978 NS_HTML5_BREAK(starttagloop);
979 } else {
980 errStartTagInTable(name);
981 appendVoidFormToCurrent(attributes);
982 attributes = nullptr;
983 NS_HTML5_BREAK(starttagloop);
986 default: {
987 errStartTagInTable(name);
988 NS_HTML5_BREAK(intableloop);
992 intableloop_end:;
993 [[fallthrough]];
995 case IN_CAPTION: {
996 switch (group) {
997 case CAPTION:
998 case COL:
999 case COLGROUP:
1000 case TBODY_OR_THEAD_OR_TFOOT:
1001 case TR:
1002 case TD_OR_TH: {
1003 eltPos = findLastInTableScope(nsGkAtoms::caption);
1004 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1005 MOZ_ASSERT(fragment || isTemplateContents());
1006 errStrayStartTag(name);
1007 NS_HTML5_BREAK(starttagloop);
1009 generateImpliedEndTags();
1010 if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
1011 errNoCheckUnclosedElementsOnStack();
1013 while (currentPtr >= eltPos) {
1014 pop();
1016 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
1017 mode = IN_TABLE;
1018 continue;
1020 default:; // fall through
1022 [[fallthrough]];
1024 case IN_CELL: {
1025 switch (group) {
1026 case CAPTION:
1027 case COL:
1028 case COLGROUP:
1029 case TBODY_OR_THEAD_OR_TFOOT:
1030 case TR:
1031 case TD_OR_TH: {
1032 eltPos = findLastInTableScopeTdTh();
1033 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1034 errNoCellToClose();
1035 NS_HTML5_BREAK(starttagloop);
1036 } else {
1037 closeTheCell(eltPos);
1038 continue;
1041 default:; // fall through
1043 [[fallthrough]];
1045 case FRAMESET_OK: {
1046 switch (group) {
1047 case FRAMESET: {
1048 if (mode == FRAMESET_OK) {
1049 if (!currentPtr || stack[1]->getGroup() != BODY) {
1050 MOZ_ASSERT(fragment || isTemplateContents());
1051 errStrayStartTag(name);
1052 NS_HTML5_BREAK(starttagloop);
1053 } else {
1054 errFramesetStart();
1055 detachFromParent(stack[1]->node);
1056 while (currentPtr > 0) {
1057 pop();
1059 appendToCurrentNodeAndPushElement(elementName, attributes);
1060 mode = IN_FRAMESET;
1061 attributes = nullptr;
1062 NS_HTML5_BREAK(starttagloop);
1064 } else {
1065 errStrayStartTag(name);
1066 NS_HTML5_BREAK(starttagloop);
1069 case PRE_OR_LISTING:
1070 case LI:
1071 case DD_OR_DT:
1072 case BUTTON:
1073 case MARQUEE_OR_APPLET:
1074 case OBJECT:
1075 case TABLE:
1076 case AREA_OR_WBR:
1077 case KEYGEN:
1078 case BR:
1079 case EMBED:
1080 case IMG:
1081 case INPUT:
1082 case HR:
1083 case TEXTAREA:
1084 case XMP:
1085 case IFRAME:
1086 case SELECT: {
1087 if (mode == FRAMESET_OK &&
1088 !(group == INPUT &&
1089 nsHtml5Portability::
1090 lowerCaseLiteralEqualsIgnoreAsciiCaseString(
1091 "hidden", attributes->getValue(
1092 nsHtml5AttributeName::ATTR_TYPE)))) {
1093 framesetOk = false;
1094 mode = IN_BODY;
1096 [[fallthrough]];
1098 default:; // fall through
1100 [[fallthrough]];
1102 case IN_BODY: {
1103 for (;;) {
1104 switch (group) {
1105 case HTML: {
1106 errStrayStartTag(name);
1107 if (!fragment && !isTemplateContents()) {
1108 addAttributesToHtml(attributes);
1109 attributes = nullptr;
1111 NS_HTML5_BREAK(starttagloop);
1113 case BASE:
1114 case LINK_OR_BASEFONT_OR_BGSOUND:
1115 case META:
1116 case STYLE:
1117 case SCRIPT:
1118 case TITLE:
1119 case TEMPLATE: {
1120 NS_HTML5_BREAK(inbodyloop);
1122 case BODY: {
1123 if (!currentPtr || stack[1]->getGroup() != BODY ||
1124 isTemplateContents()) {
1125 MOZ_ASSERT(fragment || isTemplateContents());
1126 errStrayStartTag(name);
1127 NS_HTML5_BREAK(starttagloop);
1129 errFooSeenWhenFooOpen(name);
1130 framesetOk = false;
1131 if (mode == FRAMESET_OK) {
1132 mode = IN_BODY;
1134 if (addAttributesToBody(attributes)) {
1135 attributes = nullptr;
1137 NS_HTML5_BREAK(starttagloop);
1139 case P:
1140 case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
1141 case UL_OR_OL_OR_DL:
1142 case ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SEARCH_OR_SECTION_OR_SUMMARY: {
1143 implicitlyCloseP();
1144 appendToCurrentNodeAndPushElementMayFoster(elementName,
1145 attributes);
1146 attributes = nullptr;
1147 NS_HTML5_BREAK(starttagloop);
1149 case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: {
1150 implicitlyCloseP();
1151 if (stack[currentPtr]->getGroup() ==
1152 H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
1153 errHeadingWhenHeadingOpen();
1154 pop();
1156 appendToCurrentNodeAndPushElementMayFoster(elementName,
1157 attributes);
1158 attributes = nullptr;
1159 NS_HTML5_BREAK(starttagloop);
1161 case FIELDSET: {
1162 implicitlyCloseP();
1163 appendToCurrentNodeAndPushElementMayFoster(
1164 elementName, attributes, formPointer);
1165 attributes = nullptr;
1166 NS_HTML5_BREAK(starttagloop);
1168 case PRE_OR_LISTING: {
1169 implicitlyCloseP();
1170 appendToCurrentNodeAndPushElementMayFoster(elementName,
1171 attributes);
1172 needToDropLF = true;
1173 attributes = nullptr;
1174 NS_HTML5_BREAK(starttagloop);
1176 case FORM: {
1177 if (!!formPointer && !isTemplateContents()) {
1178 errFormWhenFormOpen();
1179 NS_HTML5_BREAK(starttagloop);
1180 } else {
1181 implicitlyCloseP();
1182 appendToCurrentNodeAndPushFormElementMayFoster(attributes);
1183 attributes = nullptr;
1184 NS_HTML5_BREAK(starttagloop);
1187 case LI:
1188 case DD_OR_DT: {
1189 eltPos = currentPtr;
1190 for (;;) {
1191 nsHtml5StackNode* node = stack[eltPos];
1192 if (node->getGroup() == group) {
1193 generateImpliedEndTagsExceptFor(node->name);
1194 if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
1195 errUnclosedElementsImplied(eltPos, name);
1197 while (currentPtr >= eltPos) {
1198 pop();
1200 break;
1201 } else if (!eltPos || (node->isSpecial() &&
1202 (node->ns != kNameSpaceID_XHTML ||
1203 (node->name != nsGkAtoms::p &&
1204 node->name != nsGkAtoms::address &&
1205 node->name != nsGkAtoms::div)))) {
1206 break;
1208 eltPos--;
1210 implicitlyCloseP();
1211 appendToCurrentNodeAndPushElementMayFoster(elementName,
1212 attributes);
1213 attributes = nullptr;
1214 NS_HTML5_BREAK(starttagloop);
1216 case PLAINTEXT: {
1217 implicitlyCloseP();
1218 appendToCurrentNodeAndPushElementMayFoster(elementName,
1219 attributes);
1220 tokenizer->setStateAndEndTagExpectation(
1221 nsHtml5Tokenizer::PLAINTEXT, elementName);
1222 attributes = nullptr;
1223 NS_HTML5_BREAK(starttagloop);
1225 case A: {
1226 int32_t activeAPos =
1227 findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(
1228 nsGkAtoms::a);
1229 if (activeAPos != -1) {
1230 errFooSeenWhenFooOpen(name);
1231 nsHtml5StackNode* activeA =
1232 listOfActiveFormattingElements[activeAPos];
1233 activeA->retain();
1234 adoptionAgencyEndTag(nsGkAtoms::a);
1235 removeFromStack(activeA);
1236 activeAPos = findInListOfActiveFormattingElements(activeA);
1237 if (activeAPos != -1) {
1238 removeFromListOfActiveFormattingElements(activeAPos);
1240 activeA->release(this);
1242 reconstructTheActiveFormattingElements();
1243 appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
1244 attributes);
1245 attributes = nullptr;
1246 NS_HTML5_BREAK(starttagloop);
1248 case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
1249 case FONT: {
1250 reconstructTheActiveFormattingElements();
1251 maybeForgetEarlierDuplicateFormattingElement(
1252 elementName->getName(), attributes);
1253 appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
1254 attributes);
1255 attributes = nullptr;
1256 NS_HTML5_BREAK(starttagloop);
1258 case NOBR: {
1259 reconstructTheActiveFormattingElements();
1260 if (nsHtml5TreeBuilder::NOT_FOUND_ON_STACK !=
1261 findLastInScope(nsGkAtoms::nobr)) {
1262 errFooSeenWhenFooOpen(name);
1263 adoptionAgencyEndTag(nsGkAtoms::nobr);
1264 reconstructTheActiveFormattingElements();
1266 appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
1267 attributes);
1268 attributes = nullptr;
1269 NS_HTML5_BREAK(starttagloop);
1271 case BUTTON: {
1272 eltPos = findLastInScope(name);
1273 if (eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1274 errFooSeenWhenFooOpen(name);
1275 generateImpliedEndTags();
1276 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
1277 errUnclosedElementsImplied(eltPos, name);
1279 while (currentPtr >= eltPos) {
1280 pop();
1282 NS_HTML5_CONTINUE(starttagloop);
1283 } else {
1284 reconstructTheActiveFormattingElements();
1285 appendToCurrentNodeAndPushElementMayFoster(
1286 elementName, attributes, formPointer);
1287 attributes = nullptr;
1288 NS_HTML5_BREAK(starttagloop);
1291 case OBJECT: {
1292 reconstructTheActiveFormattingElements();
1293 appendToCurrentNodeAndPushElementMayFoster(
1294 elementName, attributes, formPointer);
1295 insertMarker();
1296 attributes = nullptr;
1297 NS_HTML5_BREAK(starttagloop);
1299 case MARQUEE_OR_APPLET: {
1300 reconstructTheActiveFormattingElements();
1301 appendToCurrentNodeAndPushElementMayFoster(elementName,
1302 attributes);
1303 insertMarker();
1304 attributes = nullptr;
1305 NS_HTML5_BREAK(starttagloop);
1307 case TABLE: {
1308 if (!quirks) {
1309 implicitlyCloseP();
1311 appendToCurrentNodeAndPushElementMayFoster(elementName,
1312 attributes);
1313 mode = IN_TABLE;
1314 attributes = nullptr;
1315 NS_HTML5_BREAK(starttagloop);
1317 case BR:
1318 case EMBED:
1319 case AREA_OR_WBR:
1320 case KEYGEN: {
1321 reconstructTheActiveFormattingElements();
1322 [[fallthrough]];
1324 case PARAM_OR_SOURCE_OR_TRACK: {
1325 appendVoidElementToCurrentMayFoster(elementName, attributes);
1326 selfClosing = false;
1327 attributes = nullptr;
1328 NS_HTML5_BREAK(starttagloop);
1330 case HR: {
1331 implicitlyCloseP();
1332 appendVoidElementToCurrentMayFoster(elementName, attributes);
1333 selfClosing = false;
1334 attributes = nullptr;
1335 NS_HTML5_BREAK(starttagloop);
1337 case IMAGE: {
1338 errImage();
1339 elementName = nsHtml5ElementName::ELT_IMG;
1340 NS_HTML5_CONTINUE(starttagloop);
1342 case IMG:
1343 case INPUT: {
1344 reconstructTheActiveFormattingElements();
1345 appendVoidElementToCurrentMayFoster(elementName, attributes,
1346 formPointer);
1347 selfClosing = false;
1348 attributes = nullptr;
1349 NS_HTML5_BREAK(starttagloop);
1351 case TEXTAREA: {
1352 appendToCurrentNodeAndPushElementMayFoster(
1353 elementName, attributes, formPointer);
1354 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
1355 elementName);
1356 originalMode = mode;
1357 mode = TEXT;
1358 needToDropLF = true;
1359 attributes = nullptr;
1360 NS_HTML5_BREAK(starttagloop);
1362 case XMP: {
1363 implicitlyCloseP();
1364 reconstructTheActiveFormattingElements();
1365 appendToCurrentNodeAndPushElementMayFoster(elementName,
1366 attributes);
1367 originalMode = mode;
1368 mode = TEXT;
1369 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1370 elementName);
1371 attributes = nullptr;
1372 NS_HTML5_BREAK(starttagloop);
1374 case NOSCRIPT: {
1375 if (!scriptingEnabled) {
1376 reconstructTheActiveFormattingElements();
1377 appendToCurrentNodeAndPushElementMayFoster(elementName,
1378 attributes);
1379 attributes = nullptr;
1380 NS_HTML5_BREAK(starttagloop);
1382 [[fallthrough]];
1384 case NOFRAMES:
1385 case IFRAME:
1386 case NOEMBED: {
1387 startTagGenericRawText(elementName, attributes);
1388 attributes = nullptr;
1389 NS_HTML5_BREAK(starttagloop);
1391 case SELECT: {
1392 reconstructTheActiveFormattingElements();
1393 appendToCurrentNodeAndPushElementMayFoster(
1394 elementName, attributes, formPointer);
1395 switch (mode) {
1396 case IN_TABLE:
1397 case IN_CAPTION:
1398 case IN_COLUMN_GROUP:
1399 case IN_TABLE_BODY:
1400 case IN_ROW:
1401 case IN_CELL: {
1402 mode = IN_SELECT_IN_TABLE;
1403 break;
1405 default: {
1406 mode = IN_SELECT;
1407 break;
1410 attributes = nullptr;
1411 NS_HTML5_BREAK(starttagloop);
1413 case OPTGROUP:
1414 case OPTION: {
1415 if (isCurrent(nsGkAtoms::option)) {
1416 pop();
1418 reconstructTheActiveFormattingElements();
1419 appendToCurrentNodeAndPushElementMayFoster(elementName,
1420 attributes);
1421 attributes = nullptr;
1422 NS_HTML5_BREAK(starttagloop);
1424 case RB_OR_RTC: {
1425 eltPos = findLastInScope(nsGkAtoms::ruby);
1426 if (eltPos != NOT_FOUND_ON_STACK) {
1427 generateImpliedEndTags();
1429 if (eltPos != currentPtr) {
1430 if (eltPos == NOT_FOUND_ON_STACK) {
1431 errStartTagSeenWithoutRuby(name);
1432 } else {
1433 errUnclosedChildrenInRuby();
1436 appendToCurrentNodeAndPushElementMayFoster(elementName,
1437 attributes);
1438 attributes = nullptr;
1439 NS_HTML5_BREAK(starttagloop);
1441 case RT_OR_RP: {
1442 eltPos = findLastInScope(nsGkAtoms::ruby);
1443 if (eltPos != NOT_FOUND_ON_STACK) {
1444 generateImpliedEndTagsExceptFor(nsGkAtoms::rtc);
1446 if (eltPos != currentPtr) {
1447 if (!isCurrent(nsGkAtoms::rtc)) {
1448 if (eltPos == NOT_FOUND_ON_STACK) {
1449 errStartTagSeenWithoutRuby(name);
1450 } else {
1451 errUnclosedChildrenInRuby();
1455 appendToCurrentNodeAndPushElementMayFoster(elementName,
1456 attributes);
1457 attributes = nullptr;
1458 NS_HTML5_BREAK(starttagloop);
1460 case MATH: {
1461 reconstructTheActiveFormattingElements();
1462 attributes->adjustForMath();
1463 if (selfClosing) {
1464 appendVoidElementToCurrentMayFosterMathML(elementName,
1465 attributes);
1466 selfClosing = false;
1467 } else {
1468 appendToCurrentNodeAndPushElementMayFosterMathML(elementName,
1469 attributes);
1471 attributes = nullptr;
1472 NS_HTML5_BREAK(starttagloop);
1474 case SVG: {
1475 reconstructTheActiveFormattingElements();
1476 attributes->adjustForSvg();
1477 if (selfClosing) {
1478 appendVoidElementToCurrentMayFosterSVG(elementName, attributes);
1479 selfClosing = false;
1480 } else {
1481 appendToCurrentNodeAndPushElementMayFosterSVG(elementName,
1482 attributes);
1484 attributes = nullptr;
1485 NS_HTML5_BREAK(starttagloop);
1487 case CAPTION:
1488 case COL:
1489 case COLGROUP:
1490 case TBODY_OR_THEAD_OR_TFOOT:
1491 case TR:
1492 case TD_OR_TH:
1493 case FRAME:
1494 case FRAMESET:
1495 case HEAD: {
1496 errStrayStartTag(name);
1497 NS_HTML5_BREAK(starttagloop);
1499 case OUTPUT: {
1500 reconstructTheActiveFormattingElements();
1501 appendToCurrentNodeAndPushElementMayFoster(
1502 elementName, attributes, formPointer);
1503 attributes = nullptr;
1504 NS_HTML5_BREAK(starttagloop);
1506 default: {
1507 reconstructTheActiveFormattingElements();
1508 appendToCurrentNodeAndPushElementMayFoster(elementName,
1509 attributes);
1510 attributes = nullptr;
1511 NS_HTML5_BREAK(starttagloop);
1515 inbodyloop_end:;
1516 [[fallthrough]];
1518 case IN_HEAD: {
1519 for (;;) {
1520 switch (group) {
1521 case HTML: {
1522 errStrayStartTag(name);
1523 if (!fragment && !isTemplateContents()) {
1524 addAttributesToHtml(attributes);
1525 attributes = nullptr;
1527 NS_HTML5_BREAK(starttagloop);
1529 case BASE:
1530 case LINK_OR_BASEFONT_OR_BGSOUND: {
1531 appendVoidElementToCurrentMayFoster(elementName, attributes);
1532 selfClosing = false;
1533 attributes = nullptr;
1534 NS_HTML5_BREAK(starttagloop);
1536 case META: {
1537 NS_HTML5_BREAK(inheadloop);
1539 case TITLE: {
1540 startTagTitleInHead(elementName, attributes);
1541 attributes = nullptr;
1542 NS_HTML5_BREAK(starttagloop);
1544 case NOSCRIPT: {
1545 if (scriptingEnabled) {
1546 appendToCurrentNodeAndPushElement(elementName, attributes);
1547 originalMode = mode;
1548 mode = TEXT;
1549 tokenizer->setStateAndEndTagExpectation(
1550 nsHtml5Tokenizer::RAWTEXT, elementName);
1551 } else {
1552 appendToCurrentNodeAndPushElementMayFoster(elementName,
1553 attributes);
1554 mode = IN_HEAD_NOSCRIPT;
1556 attributes = nullptr;
1557 NS_HTML5_BREAK(starttagloop);
1559 case SCRIPT: {
1560 startTagScriptInHead(elementName, attributes);
1561 attributes = nullptr;
1562 NS_HTML5_BREAK(starttagloop);
1564 case STYLE:
1565 case NOFRAMES: {
1566 startTagGenericRawText(elementName, attributes);
1567 attributes = nullptr;
1568 NS_HTML5_BREAK(starttagloop);
1570 case HEAD: {
1571 errFooSeenWhenFooOpen(name);
1572 NS_HTML5_BREAK(starttagloop);
1574 case TEMPLATE: {
1575 startTagTemplateInHead(elementName, attributes);
1576 attributes = nullptr;
1577 NS_HTML5_BREAK(starttagloop);
1579 default: {
1580 pop();
1581 mode = AFTER_HEAD;
1582 NS_HTML5_CONTINUE(starttagloop);
1586 inheadloop_end:;
1587 [[fallthrough]];
1589 case IN_HEAD_NOSCRIPT: {
1590 switch (group) {
1591 case HTML: {
1592 errStrayStartTag(name);
1593 if (!fragment && !isTemplateContents()) {
1594 addAttributesToHtml(attributes);
1595 attributes = nullptr;
1597 NS_HTML5_BREAK(starttagloop);
1599 case LINK_OR_BASEFONT_OR_BGSOUND: {
1600 appendVoidElementToCurrentMayFoster(elementName, attributes);
1601 selfClosing = false;
1602 attributes = nullptr;
1603 NS_HTML5_BREAK(starttagloop);
1605 case META: {
1606 checkMetaCharset(attributes);
1607 appendVoidElementToCurrentMayFoster(elementName, attributes);
1608 selfClosing = false;
1609 attributes = nullptr;
1610 NS_HTML5_BREAK(starttagloop);
1612 case STYLE:
1613 case NOFRAMES: {
1614 appendToCurrentNodeAndPushElement(elementName, attributes);
1615 originalMode = mode;
1616 mode = TEXT;
1617 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1618 elementName);
1619 attributes = nullptr;
1620 NS_HTML5_BREAK(starttagloop);
1622 case HEAD: {
1623 errFooSeenWhenFooOpen(name);
1624 NS_HTML5_BREAK(starttagloop);
1626 case NOSCRIPT: {
1627 errFooSeenWhenFooOpen(name);
1628 NS_HTML5_BREAK(starttagloop);
1630 default: {
1631 errBadStartTagInNoscriptInHead(name);
1632 pop();
1633 mode = IN_HEAD;
1634 continue;
1638 case IN_COLUMN_GROUP: {
1639 switch (group) {
1640 case HTML: {
1641 errStrayStartTag(name);
1642 if (!fragment && !isTemplateContents()) {
1643 addAttributesToHtml(attributes);
1644 attributes = nullptr;
1646 NS_HTML5_BREAK(starttagloop);
1648 case COL: {
1649 appendVoidElementToCurrentMayFoster(elementName, attributes);
1650 selfClosing = false;
1651 attributes = nullptr;
1652 NS_HTML5_BREAK(starttagloop);
1654 case TEMPLATE: {
1655 startTagTemplateInHead(elementName, attributes);
1656 attributes = nullptr;
1657 NS_HTML5_BREAK(starttagloop);
1659 default: {
1660 if (!currentPtr || stack[currentPtr]->getGroup() == TEMPLATE) {
1661 MOZ_ASSERT(fragment || isTemplateContents());
1662 errGarbageInColgroup();
1663 NS_HTML5_BREAK(starttagloop);
1665 pop();
1666 mode = IN_TABLE;
1667 continue;
1671 case IN_SELECT_IN_TABLE: {
1672 switch (group) {
1673 case CAPTION:
1674 case TBODY_OR_THEAD_OR_TFOOT:
1675 case TR:
1676 case TD_OR_TH:
1677 case TABLE: {
1678 errStartTagWithSelectOpen(name);
1679 eltPos = findLastInTableScope(nsGkAtoms::select);
1680 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1681 MOZ_ASSERT(fragment);
1682 NS_HTML5_BREAK(starttagloop);
1684 while (currentPtr >= eltPos) {
1685 pop();
1687 resetTheInsertionMode();
1688 continue;
1690 default:; // fall through
1692 [[fallthrough]];
1694 case IN_SELECT: {
1695 switch (group) {
1696 case HTML: {
1697 errStrayStartTag(name);
1698 if (!fragment) {
1699 addAttributesToHtml(attributes);
1700 attributes = nullptr;
1702 NS_HTML5_BREAK(starttagloop);
1704 case OPTION: {
1705 if (isCurrent(nsGkAtoms::option)) {
1706 pop();
1708 appendToCurrentNodeAndPushElement(elementName, attributes);
1709 attributes = nullptr;
1710 NS_HTML5_BREAK(starttagloop);
1712 case OPTGROUP: {
1713 if (isCurrent(nsGkAtoms::option)) {
1714 pop();
1716 if (isCurrent(nsGkAtoms::optgroup)) {
1717 pop();
1719 appendToCurrentNodeAndPushElement(elementName, attributes);
1720 attributes = nullptr;
1721 NS_HTML5_BREAK(starttagloop);
1723 case SELECT: {
1724 errStartSelectWhereEndSelectExpected();
1725 eltPos = findLastInTableScope(name);
1726 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1727 MOZ_ASSERT(fragment);
1728 errNoSelectInTableScope();
1729 NS_HTML5_BREAK(starttagloop);
1730 } else {
1731 while (currentPtr >= eltPos) {
1732 pop();
1734 resetTheInsertionMode();
1735 NS_HTML5_BREAK(starttagloop);
1738 case INPUT:
1739 case TEXTAREA: {
1740 errStartTagWithSelectOpen(name);
1741 eltPos = findLastInTableScope(nsGkAtoms::select);
1742 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1743 MOZ_ASSERT(fragment);
1744 NS_HTML5_BREAK(starttagloop);
1746 while (currentPtr >= eltPos) {
1747 pop();
1749 resetTheInsertionMode();
1750 continue;
1752 case SCRIPT: {
1753 startTagScriptInHead(elementName, attributes);
1754 attributes = nullptr;
1755 NS_HTML5_BREAK(starttagloop);
1757 case TEMPLATE: {
1758 startTagTemplateInHead(elementName, attributes);
1759 attributes = nullptr;
1760 NS_HTML5_BREAK(starttagloop);
1762 default: {
1763 errStrayStartTag(name);
1764 NS_HTML5_BREAK(starttagloop);
1768 case AFTER_BODY: {
1769 switch (group) {
1770 case HTML: {
1771 errStrayStartTag(name);
1772 if (!fragment && !isTemplateContents()) {
1773 addAttributesToHtml(attributes);
1774 attributes = nullptr;
1776 NS_HTML5_BREAK(starttagloop);
1778 default: {
1779 errStrayStartTag(name);
1780 mode = framesetOk ? FRAMESET_OK : IN_BODY;
1781 continue;
1785 case IN_FRAMESET: {
1786 switch (group) {
1787 case FRAMESET: {
1788 appendToCurrentNodeAndPushElement(elementName, attributes);
1789 attributes = nullptr;
1790 NS_HTML5_BREAK(starttagloop);
1792 case FRAME: {
1793 appendVoidElementToCurrentMayFoster(elementName, attributes);
1794 selfClosing = false;
1795 attributes = nullptr;
1796 NS_HTML5_BREAK(starttagloop);
1798 default:; // fall through
1800 [[fallthrough]];
1802 case AFTER_FRAMESET: {
1803 switch (group) {
1804 case HTML: {
1805 errStrayStartTag(name);
1806 if (!fragment && !isTemplateContents()) {
1807 addAttributesToHtml(attributes);
1808 attributes = nullptr;
1810 NS_HTML5_BREAK(starttagloop);
1812 case NOFRAMES: {
1813 appendToCurrentNodeAndPushElement(elementName, attributes);
1814 originalMode = mode;
1815 mode = TEXT;
1816 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1817 elementName);
1818 attributes = nullptr;
1819 NS_HTML5_BREAK(starttagloop);
1821 default: {
1822 errStrayStartTag(name);
1823 NS_HTML5_BREAK(starttagloop);
1827 case INITIAL: {
1828 errStartTagWithoutDoctype();
1829 documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
1830 mode = BEFORE_HTML;
1831 continue;
1833 case BEFORE_HTML: {
1834 switch (group) {
1835 case HTML: {
1836 if (attributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
1837 appendHtmlElementToDocumentAndPush();
1838 } else {
1839 appendHtmlElementToDocumentAndPush(attributes);
1841 mode = BEFORE_HEAD;
1842 attributes = nullptr;
1843 NS_HTML5_BREAK(starttagloop);
1845 default: {
1846 appendHtmlElementToDocumentAndPush();
1847 mode = BEFORE_HEAD;
1848 continue;
1852 case BEFORE_HEAD: {
1853 switch (group) {
1854 case HTML: {
1855 errStrayStartTag(name);
1856 if (!fragment && !isTemplateContents()) {
1857 addAttributesToHtml(attributes);
1858 attributes = nullptr;
1860 NS_HTML5_BREAK(starttagloop);
1862 case HEAD: {
1863 appendToCurrentNodeAndPushHeadElement(attributes);
1864 mode = IN_HEAD;
1865 attributes = nullptr;
1866 NS_HTML5_BREAK(starttagloop);
1868 default: {
1869 appendToCurrentNodeAndPushHeadElement(
1870 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
1871 mode = IN_HEAD;
1872 continue;
1876 case AFTER_HEAD: {
1877 switch (group) {
1878 case HTML: {
1879 errStrayStartTag(name);
1880 if (!fragment && !isTemplateContents()) {
1881 addAttributesToHtml(attributes);
1882 attributes = nullptr;
1884 NS_HTML5_BREAK(starttagloop);
1886 case BODY: {
1887 if (!attributes->getLength()) {
1888 appendToCurrentNodeAndPushBodyElement();
1889 } else {
1890 appendToCurrentNodeAndPushBodyElement(attributes);
1892 framesetOk = false;
1893 mode = IN_BODY;
1894 attributes = nullptr;
1895 NS_HTML5_BREAK(starttagloop);
1897 case FRAMESET: {
1898 appendToCurrentNodeAndPushElement(elementName, attributes);
1899 mode = IN_FRAMESET;
1900 attributes = nullptr;
1901 NS_HTML5_BREAK(starttagloop);
1903 case TEMPLATE: {
1904 errFooBetweenHeadAndBody(name);
1905 pushHeadPointerOntoStack();
1906 nsHtml5StackNode* headOnStack = stack[currentPtr];
1907 startTagTemplateInHead(elementName, attributes);
1908 removeFromStack(headOnStack);
1909 attributes = nullptr;
1910 NS_HTML5_BREAK(starttagloop);
1912 case BASE:
1913 case LINK_OR_BASEFONT_OR_BGSOUND: {
1914 errFooBetweenHeadAndBody(name);
1915 pushHeadPointerOntoStack();
1916 appendVoidElementToCurrentMayFoster(elementName, attributes);
1917 selfClosing = false;
1918 pop();
1919 attributes = nullptr;
1920 NS_HTML5_BREAK(starttagloop);
1922 case META: {
1923 errFooBetweenHeadAndBody(name);
1924 checkMetaCharset(attributes);
1925 pushHeadPointerOntoStack();
1926 appendVoidElementToCurrentMayFoster(elementName, attributes);
1927 selfClosing = false;
1928 pop();
1929 attributes = nullptr;
1930 NS_HTML5_BREAK(starttagloop);
1932 case SCRIPT: {
1933 errFooBetweenHeadAndBody(name);
1934 pushHeadPointerOntoStack();
1935 appendToCurrentNodeAndPushElement(elementName, attributes);
1936 originalMode = mode;
1937 mode = TEXT;
1938 tokenizer->setStateAndEndTagExpectation(
1939 nsHtml5Tokenizer::SCRIPT_DATA, elementName);
1940 attributes = nullptr;
1941 NS_HTML5_BREAK(starttagloop);
1943 case STYLE:
1944 case NOFRAMES: {
1945 errFooBetweenHeadAndBody(name);
1946 pushHeadPointerOntoStack();
1947 appendToCurrentNodeAndPushElement(elementName, attributes);
1948 originalMode = mode;
1949 mode = TEXT;
1950 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1951 elementName);
1952 attributes = nullptr;
1953 NS_HTML5_BREAK(starttagloop);
1955 case TITLE: {
1956 errFooBetweenHeadAndBody(name);
1957 pushHeadPointerOntoStack();
1958 appendToCurrentNodeAndPushElement(elementName, attributes);
1959 originalMode = mode;
1960 mode = TEXT;
1961 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
1962 elementName);
1963 attributes = nullptr;
1964 NS_HTML5_BREAK(starttagloop);
1966 case HEAD: {
1967 errStrayStartTag(name);
1968 NS_HTML5_BREAK(starttagloop);
1970 default: {
1971 appendToCurrentNodeAndPushBodyElement();
1972 mode = FRAMESET_OK;
1973 continue;
1977 case AFTER_AFTER_BODY: {
1978 switch (group) {
1979 case HTML: {
1980 errStrayStartTag(name);
1981 if (!fragment && !isTemplateContents()) {
1982 addAttributesToHtml(attributes);
1983 attributes = nullptr;
1985 NS_HTML5_BREAK(starttagloop);
1987 default: {
1988 errStrayStartTag(name);
1990 mode = framesetOk ? FRAMESET_OK : IN_BODY;
1991 continue;
1995 case AFTER_AFTER_FRAMESET: {
1996 switch (group) {
1997 case HTML: {
1998 errStrayStartTag(name);
1999 if (!fragment && !isTemplateContents()) {
2000 addAttributesToHtml(attributes);
2001 attributes = nullptr;
2003 NS_HTML5_BREAK(starttagloop);
2005 case NOFRAMES: {
2006 startTagGenericRawText(elementName, attributes);
2007 attributes = nullptr;
2008 NS_HTML5_BREAK(starttagloop);
2010 default: {
2011 errStrayStartTag(name);
2012 NS_HTML5_BREAK(starttagloop);
2016 case TEXT: {
2017 MOZ_ASSERT(false);
2018 NS_HTML5_BREAK(starttagloop);
2022 starttagloop_end:;
2023 if (selfClosing) {
2024 errSelfClosing();
2026 if (!mBuilder && attributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
2027 delete attributes;
2031 void nsHtml5TreeBuilder::startTagTitleInHead(
2032 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2033 appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
2034 originalMode = mode;
2035 mode = TEXT;
2036 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
2037 elementName);
2040 void nsHtml5TreeBuilder::startTagGenericRawText(
2041 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2042 appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
2043 originalMode = mode;
2044 mode = TEXT;
2045 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
2046 elementName);
2049 void nsHtml5TreeBuilder::startTagScriptInHead(
2050 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2051 appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
2052 originalMode = mode;
2053 mode = TEXT;
2054 tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::SCRIPT_DATA,
2055 elementName);
2058 void nsHtml5TreeBuilder::startTagTemplateInHead(
2059 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2060 appendToCurrentNodeAndPushElement(elementName, attributes);
2061 insertMarker();
2062 framesetOk = false;
2063 originalMode = mode;
2064 mode = IN_TEMPLATE;
2065 pushTemplateMode(IN_TEMPLATE);
2068 bool nsHtml5TreeBuilder::isTemplateContents() {
2069 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK !=
2070 findLast(nsGkAtoms::_template);
2073 bool nsHtml5TreeBuilder::isTemplateModeStackEmpty() {
2074 return templateModePtr == -1;
2077 bool nsHtml5TreeBuilder::isSpecialParentInForeign(nsHtml5StackNode* stackNode) {
2078 int32_t ns = stackNode->ns;
2079 return (kNameSpaceID_XHTML == ns) || (stackNode->isHtmlIntegrationPoint()) ||
2080 ((kNameSpaceID_MathML == ns) &&
2081 (stackNode->getGroup() == MI_MO_MN_MS_MTEXT));
2084 nsHtml5String nsHtml5TreeBuilder::extractCharsetFromContent(
2085 nsHtml5String attributeValue, nsHtml5TreeBuilder* tb) {
2086 int32_t charsetState = CHARSET_INITIAL;
2087 int32_t start = -1;
2088 int32_t end = -1;
2089 autoJArray<char16_t, int32_t> buffer =
2090 nsHtml5Portability::newCharArrayFromString(attributeValue);
2091 for (int32_t i = 0; i < buffer.length; i++) {
2092 char16_t c = buffer[i];
2093 switch (charsetState) {
2094 case CHARSET_INITIAL: {
2095 switch (c) {
2096 case 'c':
2097 case 'C': {
2098 charsetState = CHARSET_C;
2099 continue;
2101 default: {
2102 continue;
2106 case CHARSET_C: {
2107 switch (c) {
2108 case 'h':
2109 case 'H': {
2110 charsetState = CHARSET_H;
2111 continue;
2113 default: {
2114 charsetState = CHARSET_INITIAL;
2115 continue;
2119 case CHARSET_H: {
2120 switch (c) {
2121 case 'a':
2122 case 'A': {
2123 charsetState = CHARSET_A;
2124 continue;
2126 default: {
2127 charsetState = CHARSET_INITIAL;
2128 continue;
2132 case CHARSET_A: {
2133 switch (c) {
2134 case 'r':
2135 case 'R': {
2136 charsetState = CHARSET_R;
2137 continue;
2139 default: {
2140 charsetState = CHARSET_INITIAL;
2141 continue;
2145 case CHARSET_R: {
2146 switch (c) {
2147 case 's':
2148 case 'S': {
2149 charsetState = CHARSET_S;
2150 continue;
2152 default: {
2153 charsetState = CHARSET_INITIAL;
2154 continue;
2158 case CHARSET_S: {
2159 switch (c) {
2160 case 'e':
2161 case 'E': {
2162 charsetState = CHARSET_E;
2163 continue;
2165 default: {
2166 charsetState = CHARSET_INITIAL;
2167 continue;
2171 case CHARSET_E: {
2172 switch (c) {
2173 case 't':
2174 case 'T': {
2175 charsetState = CHARSET_T;
2176 continue;
2178 default: {
2179 charsetState = CHARSET_INITIAL;
2180 continue;
2184 case CHARSET_T: {
2185 switch (c) {
2186 case '\t':
2187 case '\n':
2188 case '\f':
2189 case '\r':
2190 case ' ': {
2191 continue;
2193 case '=': {
2194 charsetState = CHARSET_EQUALS;
2195 continue;
2197 default: {
2198 return nullptr;
2202 case CHARSET_EQUALS: {
2203 switch (c) {
2204 case '\t':
2205 case '\n':
2206 case '\f':
2207 case '\r':
2208 case ' ': {
2209 continue;
2211 case '\'': {
2212 start = i + 1;
2213 charsetState = CHARSET_SINGLE_QUOTED;
2214 continue;
2216 case '\"': {
2217 start = i + 1;
2218 charsetState = CHARSET_DOUBLE_QUOTED;
2219 continue;
2221 default: {
2222 start = i;
2223 charsetState = CHARSET_UNQUOTED;
2224 continue;
2228 case CHARSET_SINGLE_QUOTED: {
2229 switch (c) {
2230 case '\'': {
2231 end = i;
2232 NS_HTML5_BREAK(charsetloop);
2234 default: {
2235 continue;
2239 case CHARSET_DOUBLE_QUOTED: {
2240 switch (c) {
2241 case '\"': {
2242 end = i;
2243 NS_HTML5_BREAK(charsetloop);
2245 default: {
2246 continue;
2250 case CHARSET_UNQUOTED: {
2251 switch (c) {
2252 case '\t':
2253 case '\n':
2254 case '\f':
2255 case '\r':
2256 case ' ':
2257 case ';': {
2258 end = i;
2259 NS_HTML5_BREAK(charsetloop);
2261 default: {
2262 continue;
2268 charsetloop_end:;
2269 if (start != -1) {
2270 if (end == -1) {
2271 if (charsetState == CHARSET_UNQUOTED) {
2272 end = buffer.length;
2273 } else {
2274 return nullptr;
2277 return nsHtml5Portability::newStringFromBuffer(buffer, start, end - start,
2278 tb, false);
2280 return nullptr;
2283 void nsHtml5TreeBuilder::checkMetaCharset(nsHtml5HtmlAttributes* attributes) {
2284 nsHtml5String charset =
2285 attributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
2286 if (charset) {
2287 if (tokenizer->internalEncodingDeclaration(charset)) {
2288 requestSuspension();
2289 return;
2291 return;
2293 if (!nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
2294 "content-type",
2295 attributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) {
2296 return;
2298 nsHtml5String content =
2299 attributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
2300 if (content) {
2301 nsHtml5String extract =
2302 nsHtml5TreeBuilder::extractCharsetFromContent(content, this);
2303 if (extract) {
2304 if (tokenizer->internalEncodingDeclaration(extract)) {
2305 requestSuspension();
2308 extract.Release();
2312 void nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) {
2313 flushCharacters();
2314 needToDropLF = false;
2315 int32_t eltPos;
2316 int32_t group = elementName->getGroup();
2317 nsAtom* name = elementName->getName();
2318 for (;;) {
2319 if (isInForeign()) {
2320 if (stack[currentPtr]->name != name) {
2321 if (!currentPtr) {
2322 errStrayEndTag(name);
2323 } else {
2324 errEndTagDidNotMatchCurrentOpenElement(name,
2325 stack[currentPtr]->popName);
2328 eltPos = currentPtr;
2329 int32_t origPos = currentPtr;
2330 for (;;) {
2331 if (!eltPos) {
2332 MOZ_ASSERT(fragment,
2333 "We can get this close to the root of the stack in "
2334 "foreign content only in the fragment case.");
2335 NS_HTML5_BREAK(endtagloop);
2337 if (stack[eltPos]->name == name) {
2338 while (currentPtr >= eltPos) {
2339 popForeign(origPos, eltPos);
2341 NS_HTML5_BREAK(endtagloop);
2343 if (stack[--eltPos]->ns == kNameSpaceID_XHTML) {
2344 break;
2348 switch (mode) {
2349 case IN_TEMPLATE: {
2350 switch (group) {
2351 case TEMPLATE: {
2352 break;
2354 default: {
2355 errStrayEndTag(name);
2356 NS_HTML5_BREAK(endtagloop);
2359 [[fallthrough]];
2361 case IN_ROW: {
2362 switch (group) {
2363 case TR: {
2364 eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
2365 if (!eltPos) {
2366 MOZ_ASSERT(fragment || isTemplateContents());
2367 errNoTableRowToClose();
2368 NS_HTML5_BREAK(endtagloop);
2370 clearStackBackTo(eltPos);
2371 pop();
2372 mode = IN_TABLE_BODY;
2373 NS_HTML5_BREAK(endtagloop);
2375 case TABLE: {
2376 eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
2377 if (!eltPos) {
2378 MOZ_ASSERT(fragment || isTemplateContents());
2379 errNoTableRowToClose();
2380 NS_HTML5_BREAK(endtagloop);
2382 clearStackBackTo(eltPos);
2383 pop();
2384 mode = IN_TABLE_BODY;
2385 continue;
2387 case TBODY_OR_THEAD_OR_TFOOT: {
2388 if (findLastInTableScope(name) ==
2389 nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2390 errStrayEndTag(name);
2391 NS_HTML5_BREAK(endtagloop);
2393 eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
2394 if (!eltPos) {
2395 MOZ_ASSERT(fragment || isTemplateContents());
2396 errNoTableRowToClose();
2397 NS_HTML5_BREAK(endtagloop);
2399 clearStackBackTo(eltPos);
2400 pop();
2401 mode = IN_TABLE_BODY;
2402 continue;
2404 case BODY:
2405 case CAPTION:
2406 case COL:
2407 case COLGROUP:
2408 case HTML:
2409 case TD_OR_TH: {
2410 errStrayEndTag(name);
2411 NS_HTML5_BREAK(endtagloop);
2413 default:; // fall through
2415 [[fallthrough]];
2417 case IN_TABLE_BODY: {
2418 switch (group) {
2419 case TBODY_OR_THEAD_OR_TFOOT: {
2420 eltPos = findLastOrRoot(name);
2421 if (!eltPos) {
2422 errStrayEndTag(name);
2423 NS_HTML5_BREAK(endtagloop);
2425 clearStackBackTo(eltPos);
2426 pop();
2427 mode = IN_TABLE;
2428 NS_HTML5_BREAK(endtagloop);
2430 case TABLE: {
2431 eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
2432 if (!eltPos || stack[eltPos]->getGroup() == TEMPLATE) {
2433 MOZ_ASSERT(fragment || isTemplateContents());
2434 errStrayEndTag(name);
2435 NS_HTML5_BREAK(endtagloop);
2437 clearStackBackTo(eltPos);
2438 pop();
2439 mode = IN_TABLE;
2440 continue;
2442 case BODY:
2443 case CAPTION:
2444 case COL:
2445 case COLGROUP:
2446 case HTML:
2447 case TD_OR_TH:
2448 case TR: {
2449 errStrayEndTag(name);
2450 NS_HTML5_BREAK(endtagloop);
2452 default:; // fall through
2454 [[fallthrough]];
2456 case IN_TABLE: {
2457 switch (group) {
2458 case TABLE: {
2459 eltPos = findLast(nsGkAtoms::table);
2460 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2461 MOZ_ASSERT(fragment || isTemplateContents());
2462 errStrayEndTag(name);
2463 NS_HTML5_BREAK(endtagloop);
2465 while (currentPtr >= eltPos) {
2466 pop();
2468 resetTheInsertionMode();
2469 NS_HTML5_BREAK(endtagloop);
2471 case BODY:
2472 case CAPTION:
2473 case COL:
2474 case COLGROUP:
2475 case HTML:
2476 case TBODY_OR_THEAD_OR_TFOOT:
2477 case TD_OR_TH:
2478 case TR: {
2479 errStrayEndTag(name);
2480 NS_HTML5_BREAK(endtagloop);
2482 case TEMPLATE: {
2483 break;
2485 default: {
2486 errStrayEndTag(name);
2489 [[fallthrough]];
2491 case IN_CAPTION: {
2492 switch (group) {
2493 case CAPTION: {
2494 eltPos = findLastInTableScope(nsGkAtoms::caption);
2495 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2496 NS_HTML5_BREAK(endtagloop);
2498 generateImpliedEndTags();
2499 if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
2500 errUnclosedElements(eltPos, name);
2502 while (currentPtr >= eltPos) {
2503 pop();
2505 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
2506 mode = IN_TABLE;
2507 NS_HTML5_BREAK(endtagloop);
2509 case TABLE: {
2510 eltPos = findLastInTableScope(nsGkAtoms::caption);
2511 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2512 MOZ_ASSERT(fragment || isTemplateContents());
2513 errStrayEndTag(name);
2514 NS_HTML5_BREAK(endtagloop);
2516 generateImpliedEndTags();
2517 if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
2518 errUnclosedElements(eltPos, name);
2520 while (currentPtr >= eltPos) {
2521 pop();
2523 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
2524 mode = IN_TABLE;
2525 continue;
2527 case BODY:
2528 case COL:
2529 case COLGROUP:
2530 case HTML:
2531 case TBODY_OR_THEAD_OR_TFOOT:
2532 case TD_OR_TH:
2533 case TR: {
2534 errStrayEndTag(name);
2535 NS_HTML5_BREAK(endtagloop);
2537 default:; // fall through
2539 [[fallthrough]];
2541 case IN_CELL: {
2542 switch (group) {
2543 case TD_OR_TH: {
2544 eltPos = findLastInTableScope(name);
2545 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2546 errStrayEndTag(name);
2547 NS_HTML5_BREAK(endtagloop);
2549 generateImpliedEndTags();
2550 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2551 errUnclosedElements(eltPos, name);
2553 while (currentPtr >= eltPos) {
2554 pop();
2556 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
2557 mode = IN_ROW;
2558 NS_HTML5_BREAK(endtagloop);
2560 case TABLE:
2561 case TBODY_OR_THEAD_OR_TFOOT:
2562 case TR: {
2563 if (findLastInTableScope(name) ==
2564 nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2565 MOZ_ASSERT(name == nsGkAtoms::tbody || name == nsGkAtoms::tfoot ||
2566 name == nsGkAtoms::thead || fragment ||
2567 isTemplateContents());
2568 errStrayEndTag(name);
2569 NS_HTML5_BREAK(endtagloop);
2571 closeTheCell(findLastInTableScopeTdTh());
2572 continue;
2574 case BODY:
2575 case CAPTION:
2576 case COL:
2577 case COLGROUP:
2578 case HTML: {
2579 errStrayEndTag(name);
2580 NS_HTML5_BREAK(endtagloop);
2582 default:; // fall through
2584 [[fallthrough]];
2586 case FRAMESET_OK:
2587 case IN_BODY: {
2588 switch (group) {
2589 case BODY: {
2590 if (!isSecondOnStackBody()) {
2591 MOZ_ASSERT(fragment || isTemplateContents());
2592 errStrayEndTag(name);
2593 NS_HTML5_BREAK(endtagloop);
2595 MOZ_ASSERT(currentPtr >= 1);
2596 if (MOZ_UNLIKELY(mViewSource)) {
2597 for (int32_t i = 2; i <= currentPtr; i++) {
2598 switch (stack[i]->getGroup()) {
2599 case DD_OR_DT:
2600 case LI:
2601 case OPTGROUP:
2602 case OPTION:
2603 case P:
2604 case RB_OR_RTC:
2605 case RT_OR_RP:
2606 case TD_OR_TH:
2607 case TBODY_OR_THEAD_OR_TFOOT: {
2608 break;
2610 default: {
2611 errEndWithUnclosedElements(name);
2612 NS_HTML5_BREAK(uncloseloop1);
2616 uncloseloop1_end:;
2618 mode = AFTER_BODY;
2619 NS_HTML5_BREAK(endtagloop);
2621 case HTML: {
2622 if (!isSecondOnStackBody()) {
2623 MOZ_ASSERT(fragment || isTemplateContents());
2624 errStrayEndTag(name);
2625 NS_HTML5_BREAK(endtagloop);
2627 if (MOZ_UNLIKELY(mViewSource)) {
2628 for (int32_t i = 0; i <= currentPtr; i++) {
2629 switch (stack[i]->getGroup()) {
2630 case DD_OR_DT:
2631 case LI:
2632 case P:
2633 case RB_OR_RTC:
2634 case RT_OR_RP:
2635 case TBODY_OR_THEAD_OR_TFOOT:
2636 case TD_OR_TH:
2637 case BODY:
2638 case HTML: {
2639 break;
2641 default: {
2642 errEndWithUnclosedElements(name);
2643 NS_HTML5_BREAK(uncloseloop2);
2647 uncloseloop2_end:;
2649 mode = AFTER_BODY;
2650 continue;
2652 case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
2653 case UL_OR_OL_OR_DL:
2654 case PRE_OR_LISTING:
2655 case FIELDSET:
2656 case BUTTON:
2657 case ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SEARCH_OR_SECTION_OR_SUMMARY: {
2658 eltPos = findLastInScope(name);
2659 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2660 errStrayEndTag(name);
2661 } else {
2662 generateImpliedEndTags();
2663 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2664 errUnclosedElements(eltPos, name);
2666 while (currentPtr >= eltPos) {
2667 pop();
2670 NS_HTML5_BREAK(endtagloop);
2672 case FORM: {
2673 if (!isTemplateContents()) {
2674 if (!formPointer) {
2675 errStrayEndTag(name);
2676 NS_HTML5_BREAK(endtagloop);
2678 formPointer = nullptr;
2679 eltPos = findLastInScope(name);
2680 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2681 errStrayEndTag(name);
2682 NS_HTML5_BREAK(endtagloop);
2684 generateImpliedEndTags();
2685 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2686 errUnclosedElements(eltPos, name);
2688 removeFromStack(eltPos);
2689 NS_HTML5_BREAK(endtagloop);
2690 } else {
2691 eltPos = findLastInScope(name);
2692 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2693 errStrayEndTag(name);
2694 NS_HTML5_BREAK(endtagloop);
2696 generateImpliedEndTags();
2697 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2698 errUnclosedElements(eltPos, name);
2700 while (currentPtr >= eltPos) {
2701 pop();
2703 NS_HTML5_BREAK(endtagloop);
2706 case P: {
2707 eltPos = findLastInButtonScope(nsGkAtoms::p);
2708 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2709 errNoElementToCloseButEndTagSeen(nsGkAtoms::p);
2710 if (isInForeign()) {
2711 errHtmlStartTagInForeignContext(name);
2712 while (currentPtr >= 0 &&
2713 stack[currentPtr]->ns != kNameSpaceID_XHTML) {
2714 pop();
2717 appendVoidElementToCurrentMayFoster(
2718 elementName, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
2719 NS_HTML5_BREAK(endtagloop);
2721 generateImpliedEndTagsExceptFor(nsGkAtoms::p);
2722 MOZ_ASSERT(eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK);
2723 if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
2724 errUnclosedElements(eltPos, name);
2726 while (currentPtr >= eltPos) {
2727 pop();
2729 NS_HTML5_BREAK(endtagloop);
2731 case LI: {
2732 eltPos = findLastInListScope(name);
2733 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2734 errNoElementToCloseButEndTagSeen(name);
2735 } else {
2736 generateImpliedEndTagsExceptFor(name);
2737 if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
2738 errUnclosedElements(eltPos, name);
2740 while (currentPtr >= eltPos) {
2741 pop();
2744 NS_HTML5_BREAK(endtagloop);
2746 case DD_OR_DT: {
2747 eltPos = findLastInScope(name);
2748 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2749 errNoElementToCloseButEndTagSeen(name);
2750 } else {
2751 generateImpliedEndTagsExceptFor(name);
2752 if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
2753 errUnclosedElements(eltPos, name);
2755 while (currentPtr >= eltPos) {
2756 pop();
2759 NS_HTML5_BREAK(endtagloop);
2761 case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: {
2762 eltPos = findLastInScopeHn();
2763 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2764 errStrayEndTag(name);
2765 } else {
2766 generateImpliedEndTags();
2767 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2768 errUnclosedElements(eltPos, name);
2770 while (currentPtr >= eltPos) {
2771 pop();
2774 NS_HTML5_BREAK(endtagloop);
2776 case OBJECT:
2777 case MARQUEE_OR_APPLET: {
2778 eltPos = findLastInScope(name);
2779 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2780 errStrayEndTag(name);
2781 } else {
2782 generateImpliedEndTags();
2783 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2784 errUnclosedElements(eltPos, name);
2786 while (currentPtr >= eltPos) {
2787 pop();
2789 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
2791 NS_HTML5_BREAK(endtagloop);
2793 case BR: {
2794 errEndTagBr();
2795 if (isInForeign()) {
2796 errHtmlStartTagInForeignContext(name);
2797 while (currentPtr >= 0 &&
2798 stack[currentPtr]->ns != kNameSpaceID_XHTML) {
2799 pop();
2802 reconstructTheActiveFormattingElements();
2803 appendVoidElementToCurrentMayFoster(
2804 elementName, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
2805 NS_HTML5_BREAK(endtagloop);
2807 case TEMPLATE: {
2808 break;
2810 case AREA_OR_WBR:
2811 case KEYGEN:
2812 case PARAM_OR_SOURCE_OR_TRACK:
2813 case EMBED:
2814 case IMG:
2815 case IMAGE:
2816 case INPUT:
2817 case HR:
2818 case IFRAME:
2819 case NOEMBED:
2820 case NOFRAMES:
2821 case SELECT:
2822 case TABLE:
2823 case TEXTAREA: {
2824 errStrayEndTag(name);
2825 NS_HTML5_BREAK(endtagloop);
2827 case NOSCRIPT: {
2828 if (scriptingEnabled) {
2829 errStrayEndTag(name);
2830 NS_HTML5_BREAK(endtagloop);
2832 [[fallthrough]];
2834 case A:
2835 case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
2836 case FONT:
2837 case NOBR: {
2838 if (adoptionAgencyEndTag(name)) {
2839 NS_HTML5_BREAK(endtagloop);
2841 [[fallthrough]];
2843 default: {
2844 if (isCurrent(name)) {
2845 pop();
2846 NS_HTML5_BREAK(endtagloop);
2848 eltPos = currentPtr;
2849 for (;;) {
2850 nsHtml5StackNode* node = stack[eltPos];
2851 if (node->ns == kNameSpaceID_XHTML && node->name == name) {
2852 generateImpliedEndTags();
2853 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2854 errUnclosedElements(eltPos, name);
2856 while (currentPtr >= eltPos) {
2857 pop();
2859 NS_HTML5_BREAK(endtagloop);
2860 } else if (!eltPos || node->isSpecial()) {
2861 errStrayEndTag(name);
2862 NS_HTML5_BREAK(endtagloop);
2864 eltPos--;
2868 [[fallthrough]];
2870 case IN_HEAD: {
2871 switch (group) {
2872 case HEAD: {
2873 pop();
2874 mode = AFTER_HEAD;
2875 NS_HTML5_BREAK(endtagloop);
2877 case BR:
2878 case HTML:
2879 case BODY: {
2880 pop();
2881 mode = AFTER_HEAD;
2882 continue;
2884 case TEMPLATE: {
2885 endTagTemplateInHead();
2886 NS_HTML5_BREAK(endtagloop);
2888 default: {
2889 errStrayEndTag(name);
2890 NS_HTML5_BREAK(endtagloop);
2894 case IN_HEAD_NOSCRIPT: {
2895 switch (group) {
2896 case NOSCRIPT: {
2897 pop();
2898 mode = IN_HEAD;
2899 NS_HTML5_BREAK(endtagloop);
2901 case BR: {
2902 errStrayEndTag(name);
2903 pop();
2904 mode = IN_HEAD;
2905 continue;
2907 default: {
2908 errStrayEndTag(name);
2909 NS_HTML5_BREAK(endtagloop);
2913 case IN_COLUMN_GROUP: {
2914 switch (group) {
2915 case COLGROUP: {
2916 if (!currentPtr ||
2917 stack[currentPtr]->getGroup() == nsHtml5TreeBuilder::TEMPLATE) {
2918 MOZ_ASSERT(fragment || isTemplateContents());
2919 errGarbageInColgroup();
2920 NS_HTML5_BREAK(endtagloop);
2922 pop();
2923 mode = IN_TABLE;
2924 NS_HTML5_BREAK(endtagloop);
2926 case COL: {
2927 errStrayEndTag(name);
2928 NS_HTML5_BREAK(endtagloop);
2930 case TEMPLATE: {
2931 endTagTemplateInHead();
2932 NS_HTML5_BREAK(endtagloop);
2934 default: {
2935 if (!currentPtr ||
2936 stack[currentPtr]->getGroup() == nsHtml5TreeBuilder::TEMPLATE) {
2937 MOZ_ASSERT(fragment || isTemplateContents());
2938 errGarbageInColgroup();
2939 NS_HTML5_BREAK(endtagloop);
2941 pop();
2942 mode = IN_TABLE;
2943 continue;
2947 case IN_SELECT_IN_TABLE: {
2948 switch (group) {
2949 case CAPTION:
2950 case TABLE:
2951 case TBODY_OR_THEAD_OR_TFOOT:
2952 case TR:
2953 case TD_OR_TH: {
2954 errEndTagSeenWithSelectOpen(name);
2955 if (findLastInTableScope(name) !=
2956 nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2957 eltPos = findLastInTableScope(nsGkAtoms::select);
2958 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2959 MOZ_ASSERT(fragment);
2960 NS_HTML5_BREAK(endtagloop);
2962 while (currentPtr >= eltPos) {
2963 pop();
2965 resetTheInsertionMode();
2966 continue;
2967 } else {
2968 NS_HTML5_BREAK(endtagloop);
2971 default:; // fall through
2973 [[fallthrough]];
2975 case IN_SELECT: {
2976 switch (group) {
2977 case OPTION: {
2978 if (isCurrent(nsGkAtoms::option)) {
2979 pop();
2980 NS_HTML5_BREAK(endtagloop);
2981 } else {
2982 errStrayEndTag(name);
2983 NS_HTML5_BREAK(endtagloop);
2986 case OPTGROUP: {
2987 if (isCurrent(nsGkAtoms::option) &&
2988 nsGkAtoms::optgroup == stack[currentPtr - 1]->name) {
2989 pop();
2991 if (isCurrent(nsGkAtoms::optgroup)) {
2992 pop();
2993 } else {
2994 errStrayEndTag(name);
2996 NS_HTML5_BREAK(endtagloop);
2998 case SELECT: {
2999 eltPos = findLastInTableScope(nsGkAtoms::select);
3000 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
3001 MOZ_ASSERT(fragment);
3002 errStrayEndTag(name);
3003 NS_HTML5_BREAK(endtagloop);
3005 while (currentPtr >= eltPos) {
3006 pop();
3008 resetTheInsertionMode();
3009 NS_HTML5_BREAK(endtagloop);
3011 case TEMPLATE: {
3012 endTagTemplateInHead();
3013 NS_HTML5_BREAK(endtagloop);
3015 default: {
3016 errStrayEndTag(name);
3017 NS_HTML5_BREAK(endtagloop);
3021 case AFTER_BODY: {
3022 switch (group) {
3023 case HTML: {
3024 if (fragment) {
3025 errStrayEndTag(name);
3026 NS_HTML5_BREAK(endtagloop);
3027 } else {
3028 mode = AFTER_AFTER_BODY;
3029 NS_HTML5_BREAK(endtagloop);
3032 default: {
3033 errEndTagAfterBody();
3034 mode = framesetOk ? FRAMESET_OK : IN_BODY;
3035 continue;
3039 case IN_FRAMESET: {
3040 switch (group) {
3041 case FRAMESET: {
3042 if (!currentPtr) {
3043 MOZ_ASSERT(fragment);
3044 errStrayEndTag(name);
3045 NS_HTML5_BREAK(endtagloop);
3047 pop();
3048 if ((!fragment) && !isCurrent(nsGkAtoms::frameset)) {
3049 mode = AFTER_FRAMESET;
3051 NS_HTML5_BREAK(endtagloop);
3053 default: {
3054 errStrayEndTag(name);
3055 NS_HTML5_BREAK(endtagloop);
3059 case AFTER_FRAMESET: {
3060 switch (group) {
3061 case HTML: {
3062 mode = AFTER_AFTER_FRAMESET;
3063 NS_HTML5_BREAK(endtagloop);
3065 default: {
3066 errStrayEndTag(name);
3067 NS_HTML5_BREAK(endtagloop);
3071 case INITIAL: {
3072 errEndTagSeenWithoutDoctype();
3073 documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
3074 mode = BEFORE_HTML;
3075 continue;
3077 case BEFORE_HTML: {
3078 switch (group) {
3079 case HEAD:
3080 case BR:
3081 case HTML:
3082 case BODY: {
3083 appendHtmlElementToDocumentAndPush();
3084 mode = BEFORE_HEAD;
3085 continue;
3087 default: {
3088 errStrayEndTag(name);
3089 NS_HTML5_BREAK(endtagloop);
3093 case BEFORE_HEAD: {
3094 switch (group) {
3095 case HEAD:
3096 case BR:
3097 case HTML:
3098 case BODY: {
3099 appendToCurrentNodeAndPushHeadElement(
3100 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
3101 mode = IN_HEAD;
3102 continue;
3104 default: {
3105 errStrayEndTag(name);
3106 NS_HTML5_BREAK(endtagloop);
3110 case AFTER_HEAD: {
3111 switch (group) {
3112 case TEMPLATE: {
3113 endTagTemplateInHead();
3114 NS_HTML5_BREAK(endtagloop);
3116 case HTML:
3117 case BODY:
3118 case BR: {
3119 appendToCurrentNodeAndPushBodyElement();
3120 mode = FRAMESET_OK;
3121 continue;
3123 default: {
3124 errStrayEndTag(name);
3125 NS_HTML5_BREAK(endtagloop);
3129 case AFTER_AFTER_BODY: {
3130 errStrayEndTag(name);
3131 mode = framesetOk ? FRAMESET_OK : IN_BODY;
3132 continue;
3134 case AFTER_AFTER_FRAMESET: {
3135 errStrayEndTag(name);
3136 NS_HTML5_BREAK(endtagloop);
3138 case TEXT: {
3139 pop();
3140 if (originalMode == AFTER_HEAD) {
3141 silentPop();
3143 mode = originalMode;
3144 NS_HTML5_BREAK(endtagloop);
3148 endtagloop_end:;
3151 void nsHtml5TreeBuilder::endTagTemplateInHead() {
3152 int32_t eltPos = findLast(nsGkAtoms::_template);
3153 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
3154 errStrayEndTag(nsGkAtoms::_template);
3155 return;
3157 generateImpliedEndTagsThoroughly();
3158 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(nsGkAtoms::_template)) {
3159 errUnclosedElements(eltPos, nsGkAtoms::_template);
3161 while (currentPtr >= eltPos) {
3162 pop();
3164 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
3165 popTemplateMode();
3166 resetTheInsertionMode();
3169 int32_t
3170 nsHtml5TreeBuilder::findLastInTableScopeOrRootTemplateTbodyTheadTfoot() {
3171 for (int32_t i = currentPtr; i > 0; i--) {
3172 if (stack[i]->ns == kNameSpaceID_XHTML &&
3173 (stack[i]->getGroup() == nsHtml5TreeBuilder::TBODY_OR_THEAD_OR_TFOOT ||
3174 stack[i]->getGroup() == nsHtml5TreeBuilder::TEMPLATE)) {
3175 return i;
3178 return 0;
3181 int32_t nsHtml5TreeBuilder::findLast(nsAtom* name) {
3182 for (int32_t i = currentPtr; i > 0; i--) {
3183 if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) {
3184 return i;
3187 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3190 int32_t nsHtml5TreeBuilder::findLastInTableScope(nsAtom* name) {
3191 for (int32_t i = currentPtr; i > 0; i--) {
3192 if (stack[i]->ns == kNameSpaceID_XHTML) {
3193 if (stack[i]->name == name) {
3194 return i;
3195 } else if (stack[i]->name == nsGkAtoms::table ||
3196 stack[i]->name == nsGkAtoms::_template) {
3197 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3201 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3204 int32_t nsHtml5TreeBuilder::findLastInButtonScope(nsAtom* name) {
3205 for (int32_t i = currentPtr; i > 0; i--) {
3206 if (stack[i]->ns == kNameSpaceID_XHTML) {
3207 if (stack[i]->name == name) {
3208 return i;
3209 } else if (stack[i]->name == nsGkAtoms::button) {
3210 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3213 if (stack[i]->isScoping()) {
3214 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3217 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3220 int32_t nsHtml5TreeBuilder::findLastInScope(nsAtom* name) {
3221 for (int32_t i = currentPtr; i > 0; i--) {
3222 if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) {
3223 return i;
3224 } else if (stack[i]->isScoping()) {
3225 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3228 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3231 int32_t nsHtml5TreeBuilder::findLastInListScope(nsAtom* name) {
3232 for (int32_t i = currentPtr; i > 0; i--) {
3233 if (stack[i]->ns == kNameSpaceID_XHTML) {
3234 if (stack[i]->name == name) {
3235 return i;
3236 } else if (stack[i]->name == nsGkAtoms::ul ||
3237 stack[i]->name == nsGkAtoms::ol) {
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::findLastInScopeHn() {
3249 for (int32_t i = currentPtr; i > 0; i--) {
3250 if (stack[i]->getGroup() ==
3251 nsHtml5TreeBuilder::H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
3252 return i;
3253 } else if (stack[i]->isScoping()) {
3254 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3257 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3260 void nsHtml5TreeBuilder::generateImpliedEndTagsExceptFor(nsAtom* name) {
3261 for (;;) {
3262 nsHtml5StackNode* node = stack[currentPtr];
3263 switch (node->getGroup()) {
3264 case P:
3265 case LI:
3266 case DD_OR_DT:
3267 case OPTION:
3268 case OPTGROUP:
3269 case RB_OR_RTC:
3270 case RT_OR_RP: {
3271 if (node->ns == kNameSpaceID_XHTML && node->name == name) {
3272 return;
3274 pop();
3275 continue;
3277 default: {
3278 return;
3284 void nsHtml5TreeBuilder::generateImpliedEndTags() {
3285 for (;;) {
3286 switch (stack[currentPtr]->getGroup()) {
3287 case P:
3288 case LI:
3289 case DD_OR_DT:
3290 case OPTION:
3291 case OPTGROUP:
3292 case RB_OR_RTC:
3293 case RT_OR_RP: {
3294 pop();
3295 continue;
3297 default: {
3298 return;
3304 void nsHtml5TreeBuilder::generateImpliedEndTagsThoroughly() {
3305 for (;;) {
3306 switch (stack[currentPtr]->getGroup()) {
3307 case CAPTION:
3308 case COLGROUP:
3309 case DD_OR_DT:
3310 case LI:
3311 case OPTGROUP:
3312 case OPTION:
3313 case P:
3314 case RB_OR_RTC:
3315 case RT_OR_RP:
3316 case TBODY_OR_THEAD_OR_TFOOT:
3317 case TD_OR_TH:
3318 case TR: {
3319 pop();
3320 continue;
3322 default: {
3323 return;
3329 bool nsHtml5TreeBuilder::isSecondOnStackBody() {
3330 return currentPtr >= 1 && stack[1]->getGroup() == nsHtml5TreeBuilder::BODY;
3333 void nsHtml5TreeBuilder::documentModeInternal(nsHtml5DocumentMode m,
3334 nsHtml5String publicIdentifier,
3335 nsHtml5String systemIdentifier) {
3336 if (forceNoQuirks) {
3337 quirks = false;
3338 this->documentMode(STANDARDS_MODE);
3339 return;
3341 quirks = (m == QUIRKS_MODE);
3342 this->documentMode(m);
3345 bool nsHtml5TreeBuilder::isAlmostStandards(nsHtml5String publicIdentifier,
3346 nsHtml5String systemIdentifier) {
3347 if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3348 "-//w3c//dtd xhtml 1.0 transitional//", publicIdentifier)) {
3349 return true;
3351 if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3352 "-//w3c//dtd xhtml 1.0 frameset//", publicIdentifier)) {
3353 return true;
3355 if (systemIdentifier) {
3356 if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3357 "-//w3c//dtd html 4.01 transitional//", publicIdentifier)) {
3358 return true;
3360 if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3361 "-//w3c//dtd html 4.01 frameset//", publicIdentifier)) {
3362 return true;
3365 return false;
3368 bool nsHtml5TreeBuilder::isQuirky(nsAtom* name, nsHtml5String publicIdentifier,
3369 nsHtml5String systemIdentifier,
3370 bool forceQuirks) {
3371 if (forceQuirks) {
3372 return true;
3374 if (name != nsGkAtoms::html) {
3375 return true;
3377 if (publicIdentifier) {
3378 for (int32_t i = 0; i < nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS.length; i++) {
3379 if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3380 nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS[i], publicIdentifier)) {
3381 return true;
3384 if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
3385 "-//w3o//dtd w3 html strict 3.0//en//", publicIdentifier) ||
3386 nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
3387 "-/w3c/dtd html 4.0 transitional/en", publicIdentifier) ||
3388 nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
3389 "html", publicIdentifier)) {
3390 return true;
3393 if (!systemIdentifier) {
3394 if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3395 "-//w3c//dtd html 4.01 transitional//", publicIdentifier)) {
3396 return true;
3397 } else if (nsHtml5Portability::
3398 lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3399 "-//w3c//dtd html 4.01 frameset//", publicIdentifier)) {
3400 return true;
3402 } else if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
3403 "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd",
3404 systemIdentifier)) {
3405 return true;
3407 return false;
3410 void nsHtml5TreeBuilder::closeTheCell(int32_t eltPos) {
3411 generateImpliedEndTags();
3412 if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
3413 errUnclosedElementsCell(eltPos);
3415 while (currentPtr >= eltPos) {
3416 pop();
3418 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
3419 mode = IN_ROW;
3420 return;
3423 int32_t nsHtml5TreeBuilder::findLastInTableScopeTdTh() {
3424 for (int32_t i = currentPtr; i > 0; i--) {
3425 nsAtom* name = stack[i]->name;
3426 if (stack[i]->ns == kNameSpaceID_XHTML) {
3427 if (nsGkAtoms::td == name || nsGkAtoms::th == name) {
3428 return i;
3429 } else if (name == nsGkAtoms::table || name == nsGkAtoms::_template) {
3430 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3434 return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3437 void nsHtml5TreeBuilder::clearStackBackTo(int32_t eltPos) {
3438 int32_t eltGroup = stack[eltPos]->getGroup();
3439 while (currentPtr > eltPos) {
3440 if (stack[currentPtr]->ns == kNameSpaceID_XHTML &&
3441 stack[currentPtr]->getGroup() == TEMPLATE &&
3442 (eltGroup == TABLE || eltGroup == TBODY_OR_THEAD_OR_TFOOT ||
3443 eltGroup == TR || !eltPos)) {
3444 return;
3446 pop();
3450 void nsHtml5TreeBuilder::resetTheInsertionMode() {
3451 nsHtml5StackNode* node;
3452 nsAtom* name;
3453 int32_t ns;
3454 for (int32_t i = currentPtr; i >= 0; i--) {
3455 node = stack[i];
3456 name = node->name;
3457 ns = node->ns;
3458 if (!i) {
3459 if (!(contextNamespace == kNameSpaceID_XHTML &&
3460 (contextName == nsGkAtoms::td || contextName == nsGkAtoms::th))) {
3461 if (fragment) {
3462 name = contextName;
3463 ns = contextNamespace;
3465 } else {
3466 mode = framesetOk ? FRAMESET_OK : IN_BODY;
3467 return;
3470 if (nsGkAtoms::select == name) {
3471 int32_t ancestorIndex = i;
3472 while (ancestorIndex > 0) {
3473 nsHtml5StackNode* ancestor = stack[ancestorIndex--];
3474 if (kNameSpaceID_XHTML == ancestor->ns) {
3475 if (nsGkAtoms::_template == ancestor->name) {
3476 break;
3478 if (nsGkAtoms::table == ancestor->name) {
3479 mode = IN_SELECT_IN_TABLE;
3480 return;
3484 mode = IN_SELECT;
3485 return;
3486 } else if (nsGkAtoms::td == name || nsGkAtoms::th == name) {
3487 mode = IN_CELL;
3488 return;
3489 } else if (nsGkAtoms::tr == name) {
3490 mode = IN_ROW;
3491 return;
3492 } else if (nsGkAtoms::tbody == name || nsGkAtoms::thead == name ||
3493 nsGkAtoms::tfoot == name) {
3494 mode = IN_TABLE_BODY;
3495 return;
3496 } else if (nsGkAtoms::caption == name) {
3497 mode = IN_CAPTION;
3498 return;
3499 } else if (nsGkAtoms::colgroup == name) {
3500 mode = IN_COLUMN_GROUP;
3501 return;
3502 } else if (nsGkAtoms::table == name) {
3503 mode = IN_TABLE;
3504 return;
3505 } else if (kNameSpaceID_XHTML != ns) {
3506 mode = framesetOk ? FRAMESET_OK : IN_BODY;
3507 return;
3508 } else if (nsGkAtoms::_template == name) {
3509 MOZ_ASSERT(templateModePtr >= 0);
3510 mode = templateModeStack[templateModePtr];
3511 return;
3512 } else if (nsGkAtoms::head == name) {
3513 if (name == contextName) {
3514 mode = framesetOk ? FRAMESET_OK : IN_BODY;
3515 } else {
3516 mode = IN_HEAD;
3518 return;
3519 } else if (nsGkAtoms::body == name) {
3520 mode = framesetOk ? FRAMESET_OK : IN_BODY;
3521 return;
3522 } else if (nsGkAtoms::frameset == name) {
3523 mode = IN_FRAMESET;
3524 return;
3525 } else if (nsGkAtoms::html == name) {
3526 if (!headPointer) {
3527 mode = BEFORE_HEAD;
3528 } else {
3529 mode = AFTER_HEAD;
3531 return;
3532 } else if (!i) {
3533 mode = framesetOk ? FRAMESET_OK : IN_BODY;
3534 return;
3539 void nsHtml5TreeBuilder::implicitlyCloseP() {
3540 int32_t eltPos = findLastInButtonScope(nsGkAtoms::p);
3541 if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
3542 return;
3544 generateImpliedEndTagsExceptFor(nsGkAtoms::p);
3545 if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
3546 errUnclosedElementsImplied(eltPos, nsGkAtoms::p);
3548 while (currentPtr >= eltPos) {
3549 pop();
3553 bool nsHtml5TreeBuilder::debugOnlyClearLastStackSlot() {
3554 stack[currentPtr] = nullptr;
3555 return true;
3558 bool nsHtml5TreeBuilder::debugOnlyClearLastListSlot() {
3559 listOfActiveFormattingElements[listPtr] = nullptr;
3560 return true;
3563 void nsHtml5TreeBuilder::pushTemplateMode(int32_t mode) {
3564 templateModePtr++;
3565 if (templateModePtr == templateModeStack.length) {
3566 jArray<int32_t, int32_t> newStack =
3567 jArray<int32_t, int32_t>::newJArray(templateModeStack.length + 64);
3568 nsHtml5ArrayCopy::arraycopy(templateModeStack, newStack,
3569 templateModeStack.length);
3570 templateModeStack = newStack;
3572 templateModeStack[templateModePtr] = mode;
3575 void nsHtml5TreeBuilder::push(nsHtml5StackNode* node) {
3576 currentPtr++;
3577 if (currentPtr == stack.length) {
3578 jArray<nsHtml5StackNode*, int32_t> newStack =
3579 jArray<nsHtml5StackNode*, int32_t>::newJArray(stack.length + 64);
3580 nsHtml5ArrayCopy::arraycopy(stack, newStack, stack.length);
3581 stack = newStack;
3583 stack[currentPtr] = node;
3584 elementPushed(node->ns, node->popName, node->node);
3587 void nsHtml5TreeBuilder::silentPush(nsHtml5StackNode* node) {
3588 currentPtr++;
3589 if (currentPtr == stack.length) {
3590 jArray<nsHtml5StackNode*, int32_t> newStack =
3591 jArray<nsHtml5StackNode*, int32_t>::newJArray(stack.length + 64);
3592 nsHtml5ArrayCopy::arraycopy(stack, newStack, stack.length);
3593 stack = newStack;
3595 stack[currentPtr] = node;
3598 void nsHtml5TreeBuilder::append(nsHtml5StackNode* node) {
3599 listPtr++;
3600 if (listPtr == listOfActiveFormattingElements.length) {
3601 jArray<nsHtml5StackNode*, int32_t> newList =
3602 jArray<nsHtml5StackNode*, int32_t>::newJArray(
3603 listOfActiveFormattingElements.length + 64);
3604 nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, newList,
3605 listOfActiveFormattingElements.length);
3606 listOfActiveFormattingElements = newList;
3608 listOfActiveFormattingElements[listPtr] = node;
3611 void nsHtml5TreeBuilder::
3612 clearTheListOfActiveFormattingElementsUpToTheLastMarker() {
3613 while (listPtr > -1) {
3614 if (!listOfActiveFormattingElements[listPtr]) {
3615 --listPtr;
3616 return;
3618 listOfActiveFormattingElements[listPtr]->release(this);
3619 --listPtr;
3623 void nsHtml5TreeBuilder::removeFromStack(int32_t pos) {
3624 if (currentPtr == pos) {
3625 pop();
3626 } else {
3627 stack[pos]->release(this);
3628 nsHtml5ArrayCopy::arraycopy(stack, pos + 1, pos, currentPtr - pos);
3629 MOZ_ASSERT(debugOnlyClearLastStackSlot());
3630 currentPtr--;
3634 void nsHtml5TreeBuilder::removeFromStack(nsHtml5StackNode* node) {
3635 if (stack[currentPtr] == node) {
3636 pop();
3637 } else {
3638 int32_t pos = currentPtr - 1;
3639 while (pos >= 0 && stack[pos] != node) {
3640 pos--;
3642 if (pos == -1) {
3643 return;
3646 node->release(this);
3647 nsHtml5ArrayCopy::arraycopy(stack, pos + 1, pos, currentPtr - pos);
3648 currentPtr--;
3652 void nsHtml5TreeBuilder::removeFromListOfActiveFormattingElements(int32_t pos) {
3653 MOZ_ASSERT(!!listOfActiveFormattingElements[pos]);
3654 listOfActiveFormattingElements[pos]->release(this);
3655 if (pos == listPtr) {
3656 MOZ_ASSERT(debugOnlyClearLastListSlot());
3657 listPtr--;
3658 return;
3660 MOZ_ASSERT(pos < listPtr);
3661 nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, pos + 1, pos,
3662 listPtr - pos);
3663 MOZ_ASSERT(debugOnlyClearLastListSlot());
3664 listPtr--;
3667 bool nsHtml5TreeBuilder::adoptionAgencyEndTag(nsAtom* name) {
3668 if (stack[currentPtr]->ns == kNameSpaceID_XHTML &&
3669 stack[currentPtr]->name == name &&
3670 findInListOfActiveFormattingElements(stack[currentPtr]) == -1) {
3671 pop();
3672 return true;
3674 for (int32_t i = 0; i < 8; ++i) {
3675 int32_t formattingEltListPos = listPtr;
3676 while (formattingEltListPos > -1) {
3677 nsHtml5StackNode* listNode =
3678 listOfActiveFormattingElements[formattingEltListPos];
3679 if (!listNode) {
3680 formattingEltListPos = -1;
3681 break;
3682 } else if (listNode->name == name) {
3683 break;
3685 formattingEltListPos--;
3687 if (formattingEltListPos == -1) {
3688 return false;
3690 nsHtml5StackNode* formattingElt =
3691 listOfActiveFormattingElements[formattingEltListPos];
3692 int32_t formattingEltStackPos = currentPtr;
3693 bool inScope = true;
3694 while (formattingEltStackPos > -1) {
3695 nsHtml5StackNode* node = stack[formattingEltStackPos];
3696 if (node == formattingElt) {
3697 break;
3698 } else if (node->isScoping()) {
3699 inScope = false;
3701 formattingEltStackPos--;
3703 if (formattingEltStackPos == -1) {
3704 errNoElementToCloseButEndTagSeen(name);
3705 removeFromListOfActiveFormattingElements(formattingEltListPos);
3706 return true;
3708 if (!inScope) {
3709 errNoElementToCloseButEndTagSeen(name);
3710 return true;
3712 if (formattingEltStackPos != currentPtr) {
3713 errEndTagViolatesNestingRules(name);
3715 int32_t furthestBlockPos = formattingEltStackPos + 1;
3716 while (furthestBlockPos <= currentPtr) {
3717 nsHtml5StackNode* node = stack[furthestBlockPos];
3718 MOZ_ASSERT(furthestBlockPos > 0,
3719 "How is formattingEltStackPos + 1 not > 0?");
3720 if (node->isSpecial()) {
3721 break;
3723 furthestBlockPos++;
3725 if (furthestBlockPos > currentPtr) {
3726 while (currentPtr >= formattingEltStackPos) {
3727 pop();
3729 removeFromListOfActiveFormattingElements(formattingEltListPos);
3730 return true;
3732 nsHtml5StackNode* commonAncestor = stack[formattingEltStackPos - 1];
3733 nsIContentHandle* insertionCommonAncestor =
3734 nodeFromStackWithBlinkCompat(formattingEltStackPos - 1);
3735 nsHtml5StackNode* furthestBlock = stack[furthestBlockPos];
3736 int32_t bookmark = formattingEltListPos;
3737 int32_t nodePos = furthestBlockPos;
3738 nsHtml5StackNode* lastNode = furthestBlock;
3739 int32_t j = 0;
3740 for (;;) {
3741 ++j;
3742 nodePos--;
3743 if (nodePos == formattingEltStackPos) {
3744 break;
3746 nsHtml5StackNode* node = stack[nodePos];
3747 int32_t nodeListPos = findInListOfActiveFormattingElements(node);
3748 if (j > 3 && nodeListPos != -1) {
3749 removeFromListOfActiveFormattingElements(nodeListPos);
3750 if (nodeListPos <= formattingEltListPos) {
3751 formattingEltListPos--;
3753 if (nodeListPos <= bookmark) {
3754 bookmark--;
3756 nodeListPos = -1;
3758 if (nodeListPos == -1) {
3759 MOZ_ASSERT(formattingEltStackPos < nodePos);
3760 MOZ_ASSERT(bookmark < nodePos);
3761 MOZ_ASSERT(furthestBlockPos > nodePos);
3762 removeFromStack(nodePos);
3763 furthestBlockPos--;
3764 continue;
3766 if (nodePos == furthestBlockPos) {
3767 bookmark = nodeListPos + 1;
3769 MOZ_ASSERT(node == listOfActiveFormattingElements[nodeListPos]);
3770 MOZ_ASSERT(node == stack[nodePos]);
3771 nsIContentHandle* clone = createElement(
3772 kNameSpaceID_XHTML, node->name, node->attributes->cloneAttributes(),
3773 insertionCommonAncestor, htmlCreator(node->getHtmlCreator()));
3774 nsHtml5StackNode* newNode = createStackNode(
3775 node->getFlags(), node->ns, node->name, clone, node->popName,
3776 node->attributes, node->getHtmlCreator());
3777 node->dropAttributes();
3778 stack[nodePos] = newNode;
3779 newNode->retain();
3780 listOfActiveFormattingElements[nodeListPos] = newNode;
3781 node->release(this);
3782 node->release(this);
3783 node = newNode;
3784 detachFromParent(lastNode->node);
3785 appendElement(lastNode->node, nodeFromStackWithBlinkCompat(nodePos));
3786 lastNode = node;
3788 if (commonAncestor->isFosterParenting()) {
3789 detachFromParent(lastNode->node);
3790 insertIntoFosterParent(lastNode->node);
3791 } else {
3792 detachFromParent(lastNode->node);
3793 appendElement(lastNode->node, insertionCommonAncestor);
3795 nsIContentHandle* clone = createElement(
3796 kNameSpaceID_XHTML, formattingElt->name,
3797 formattingElt->attributes->cloneAttributes(), furthestBlock->node,
3798 htmlCreator(formattingElt->getHtmlCreator()));
3799 nsHtml5StackNode* formattingClone = createStackNode(
3800 formattingElt->getFlags(), formattingElt->ns, formattingElt->name,
3801 clone, formattingElt->popName, formattingElt->attributes,
3802 formattingElt->getHtmlCreator());
3803 formattingElt->dropAttributes();
3804 appendChildrenToNewParent(furthestBlock->node, clone);
3805 appendElement(clone, furthestBlock->node);
3806 removeFromListOfActiveFormattingElements(formattingEltListPos);
3807 insertIntoListOfActiveFormattingElements(formattingClone, bookmark);
3808 MOZ_ASSERT(formattingEltStackPos < furthestBlockPos);
3809 removeFromStack(formattingEltStackPos);
3810 insertIntoStack(formattingClone, furthestBlockPos);
3812 return true;
3815 void nsHtml5TreeBuilder::insertIntoStack(nsHtml5StackNode* node,
3816 int32_t position) {
3817 MOZ_ASSERT(currentPtr + 1 < stack.length);
3818 MOZ_ASSERT(position <= currentPtr + 1);
3819 if (position == currentPtr + 1) {
3820 push(node);
3821 } else {
3822 nsHtml5ArrayCopy::arraycopy(stack, position, position + 1,
3823 (currentPtr - position) + 1);
3824 currentPtr++;
3825 stack[position] = node;
3829 void nsHtml5TreeBuilder::insertIntoListOfActiveFormattingElements(
3830 nsHtml5StackNode* formattingClone, int32_t bookmark) {
3831 formattingClone->retain();
3832 MOZ_ASSERT(listPtr + 1 < listOfActiveFormattingElements.length);
3833 if (bookmark <= listPtr) {
3834 nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, bookmark,
3835 bookmark + 1, (listPtr - bookmark) + 1);
3837 listPtr++;
3838 listOfActiveFormattingElements[bookmark] = formattingClone;
3841 int32_t nsHtml5TreeBuilder::findInListOfActiveFormattingElements(
3842 nsHtml5StackNode* node) {
3843 for (int32_t i = listPtr; i >= 0; i--) {
3844 if (node == listOfActiveFormattingElements[i]) {
3845 return i;
3848 return -1;
3851 int32_t nsHtml5TreeBuilder::
3852 findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(
3853 nsAtom* name) {
3854 for (int32_t i = listPtr; i >= 0; i--) {
3855 nsHtml5StackNode* node = listOfActiveFormattingElements[i];
3856 if (!node) {
3857 return -1;
3858 } else if (node->name == name) {
3859 return i;
3862 return -1;
3865 void nsHtml5TreeBuilder::maybeForgetEarlierDuplicateFormattingElement(
3866 nsAtom* name, nsHtml5HtmlAttributes* attributes) {
3867 int32_t candidate = -1;
3868 int32_t count = 0;
3869 for (int32_t i = listPtr; i >= 0; i--) {
3870 nsHtml5StackNode* node = listOfActiveFormattingElements[i];
3871 if (!node) {
3872 break;
3874 if (node->name == name && node->attributes->equalsAnother(attributes)) {
3875 candidate = i;
3876 ++count;
3879 if (count >= 3) {
3880 removeFromListOfActiveFormattingElements(candidate);
3884 int32_t nsHtml5TreeBuilder::findLastOrRoot(nsAtom* name) {
3885 for (int32_t i = currentPtr; i > 0; i--) {
3886 if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) {
3887 return i;
3890 return 0;
3893 int32_t nsHtml5TreeBuilder::findLastOrRoot(int32_t group) {
3894 for (int32_t i = currentPtr; i > 0; i--) {
3895 if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->getGroup() == group) {
3896 return i;
3899 return 0;
3902 bool nsHtml5TreeBuilder::addAttributesToBody(
3903 nsHtml5HtmlAttributes* attributes) {
3904 if (currentPtr >= 1) {
3905 nsHtml5StackNode* body = stack[1];
3906 if (body->getGroup() == nsHtml5TreeBuilder::BODY) {
3907 addAttributesToElement(body->node, attributes);
3908 return true;
3911 return false;
3914 void nsHtml5TreeBuilder::addAttributesToHtml(
3915 nsHtml5HtmlAttributes* attributes) {
3916 addAttributesToElement(stack[0]->node, attributes);
3919 void nsHtml5TreeBuilder::pushHeadPointerOntoStack() {
3920 MOZ_ASSERT(!!headPointer);
3921 MOZ_ASSERT(mode == AFTER_HEAD);
3923 silentPush(createStackNode(nsHtml5ElementName::ELT_HEAD, headPointer));
3926 void nsHtml5TreeBuilder::reconstructTheActiveFormattingElements() {
3927 if (listPtr == -1) {
3928 return;
3930 nsHtml5StackNode* mostRecent = listOfActiveFormattingElements[listPtr];
3931 if (!mostRecent || isInStack(mostRecent)) {
3932 return;
3934 int32_t entryPos = listPtr;
3935 for (;;) {
3936 entryPos--;
3937 if (entryPos == -1) {
3938 break;
3940 if (!listOfActiveFormattingElements[entryPos]) {
3941 break;
3943 if (isInStack(listOfActiveFormattingElements[entryPos])) {
3944 break;
3947 while (entryPos < listPtr) {
3948 entryPos++;
3949 nsHtml5StackNode* entry = listOfActiveFormattingElements[entryPos];
3950 nsHtml5StackNode* current = stack[currentPtr];
3951 nsIContentHandle* clone;
3952 if (current->isFosterParenting()) {
3953 clone = createAndInsertFosterParentedElement(
3954 kNameSpaceID_XHTML, entry->name, entry->attributes->cloneAttributes(),
3955 htmlCreator(entry->getHtmlCreator()));
3956 } else {
3957 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
3958 clone = createElement(kNameSpaceID_XHTML, entry->name,
3959 entry->attributes->cloneAttributes(), currentNode,
3960 htmlCreator(entry->getHtmlCreator()));
3961 appendElement(clone, currentNode);
3963 nsHtml5StackNode* entryClone = createStackNode(
3964 entry->getFlags(), entry->ns, entry->name, clone, entry->popName,
3965 entry->attributes, entry->getHtmlCreator());
3966 entry->dropAttributes();
3967 push(entryClone);
3968 listOfActiveFormattingElements[entryPos] = entryClone;
3969 entry->release(this);
3970 entryClone->retain();
3974 void nsHtml5TreeBuilder::notifyUnusedStackNode(int32_t idxInStackNodes) {
3975 if (idxInStackNodes < stackNodesIdx) {
3976 stackNodesIdx = idxInStackNodes;
3980 nsHtml5StackNode* nsHtml5TreeBuilder::getUnusedStackNode() {
3981 while (stackNodesIdx < numStackNodes) {
3982 if (stackNodes[stackNodesIdx]->isUnused()) {
3983 return stackNodes[stackNodesIdx++];
3985 stackNodesIdx++;
3987 if (stackNodesIdx < stackNodes.length) {
3988 stackNodes[stackNodesIdx] = new nsHtml5StackNode(stackNodesIdx);
3989 numStackNodes++;
3990 return stackNodes[stackNodesIdx++];
3992 jArray<nsHtml5StackNode*, int32_t> newStack =
3993 jArray<nsHtml5StackNode*, int32_t>::newJArray(stackNodes.length + 64);
3994 nsHtml5ArrayCopy::arraycopy(stackNodes, newStack, stackNodes.length);
3995 stackNodes = newStack;
3996 stackNodes[stackNodesIdx] = new nsHtml5StackNode(stackNodesIdx);
3997 numStackNodes++;
3998 return stackNodes[stackNodesIdx++];
4001 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4002 int32_t flags, int32_t ns, nsAtom* name, nsIContentHandle* node,
4003 nsAtom* popName, nsHtml5HtmlAttributes* attributes,
4004 mozilla::dom::HTMLContentCreatorFunction htmlCreator) {
4005 nsHtml5StackNode* instance = getUnusedStackNode();
4006 instance->setValues(flags, ns, name, node, popName, attributes, htmlCreator);
4007 return instance;
4010 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4011 nsHtml5ElementName* elementName, nsIContentHandle* node) {
4012 nsHtml5StackNode* instance = getUnusedStackNode();
4013 instance->setValues(elementName, node);
4014 return instance;
4017 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4018 nsHtml5ElementName* elementName, nsIContentHandle* node,
4019 nsHtml5HtmlAttributes* attributes) {
4020 nsHtml5StackNode* instance = getUnusedStackNode();
4021 instance->setValues(elementName, node, attributes);
4022 return instance;
4025 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4026 nsHtml5ElementName* elementName, nsIContentHandle* node, nsAtom* popName) {
4027 nsHtml5StackNode* instance = getUnusedStackNode();
4028 instance->setValues(elementName, node, popName);
4029 return instance;
4032 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4033 nsHtml5ElementName* elementName, nsAtom* popName, nsIContentHandle* node) {
4034 nsHtml5StackNode* instance = getUnusedStackNode();
4035 instance->setValues(elementName, popName, node);
4036 return instance;
4039 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4040 nsHtml5ElementName* elementName, nsIContentHandle* node, nsAtom* popName,
4041 bool markAsIntegrationPoint) {
4042 nsHtml5StackNode* instance = getUnusedStackNode();
4043 instance->setValues(elementName, node, popName, markAsIntegrationPoint);
4044 return instance;
4047 void nsHtml5TreeBuilder::insertIntoFosterParent(nsIContentHandle* child) {
4048 int32_t tablePos = findLastOrRoot(nsHtml5TreeBuilder::TABLE);
4049 int32_t templatePos = findLastOrRoot(nsHtml5TreeBuilder::TEMPLATE);
4050 if (templatePos >= tablePos) {
4051 appendElement(child, stack[templatePos]->node);
4052 return;
4054 nsHtml5StackNode* node = stack[tablePos];
4055 insertFosterParentedChild(child, node->node, stack[tablePos - 1]->node);
4058 nsIContentHandle* nsHtml5TreeBuilder::createAndInsertFosterParentedElement(
4059 int32_t ns, nsAtom* name, nsHtml5HtmlAttributes* attributes,
4060 nsHtml5ContentCreatorFunction creator) {
4061 return createAndInsertFosterParentedElement(ns, name, attributes, nullptr,
4062 creator);
4065 nsIContentHandle* nsHtml5TreeBuilder::createAndInsertFosterParentedElement(
4066 int32_t ns, nsAtom* name, nsHtml5HtmlAttributes* attributes,
4067 nsIContentHandle* form, nsHtml5ContentCreatorFunction creator) {
4068 int32_t tablePos = findLastOrRoot(nsHtml5TreeBuilder::TABLE);
4069 int32_t templatePos = findLastOrRoot(nsHtml5TreeBuilder::TEMPLATE);
4070 if (templatePos >= tablePos) {
4071 nsIContentHandle* child = createElement(ns, name, attributes, form,
4072 stack[templatePos]->node, creator);
4073 appendElement(child, stack[templatePos]->node);
4074 return child;
4076 nsHtml5StackNode* node = stack[tablePos];
4077 return createAndInsertFosterParentedElement(
4078 ns, name, attributes, form, node->node, stack[tablePos - 1]->node,
4079 creator);
4082 bool nsHtml5TreeBuilder::isInStack(nsHtml5StackNode* node) {
4083 for (int32_t i = currentPtr; i >= 0; i--) {
4084 if (stack[i] == node) {
4085 return true;
4088 return false;
4091 void nsHtml5TreeBuilder::popTemplateMode() { templateModePtr--; }
4093 void nsHtml5TreeBuilder::pop() {
4094 nsHtml5StackNode* node = stack[currentPtr];
4095 MOZ_ASSERT(debugOnlyClearLastStackSlot());
4096 currentPtr--;
4097 elementPopped(node->ns, node->popName, node->node);
4098 node->release(this);
4101 void nsHtml5TreeBuilder::popForeign(int32_t origPos, int32_t eltPos) {
4102 nsHtml5StackNode* node = stack[currentPtr];
4103 if (origPos != currentPtr || eltPos != currentPtr) {
4104 markMalformedIfScript(node->node);
4106 MOZ_ASSERT(debugOnlyClearLastStackSlot());
4107 currentPtr--;
4108 elementPopped(node->ns, node->popName, node->node);
4109 node->release(this);
4112 void nsHtml5TreeBuilder::silentPop() {
4113 nsHtml5StackNode* node = stack[currentPtr];
4114 MOZ_ASSERT(debugOnlyClearLastStackSlot());
4115 currentPtr--;
4116 node->release(this);
4119 void nsHtml5TreeBuilder::popOnEof() {
4120 nsHtml5StackNode* node = stack[currentPtr];
4121 MOZ_ASSERT(debugOnlyClearLastStackSlot());
4122 currentPtr--;
4123 markMalformedIfScript(node->node);
4124 elementPopped(node->ns, node->popName, node->node);
4125 node->release(this);
4128 void nsHtml5TreeBuilder::appendHtmlElementToDocumentAndPush(
4129 nsHtml5HtmlAttributes* attributes) {
4130 nsIContentHandle* elt = createHtmlElementSetAsRoot(attributes);
4131 nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_HTML, elt);
4132 push(node);
4135 void nsHtml5TreeBuilder::appendHtmlElementToDocumentAndPush() {
4136 appendHtmlElementToDocumentAndPush(tokenizer->emptyAttributes());
4139 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushHeadElement(
4140 nsHtml5HtmlAttributes* attributes) {
4141 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4142 nsIContentHandle* elt =
4143 createElement(kNameSpaceID_XHTML, nsGkAtoms::head, attributes,
4144 currentNode, htmlCreator(NS_NewHTMLSharedElement));
4145 appendElement(elt, currentNode);
4146 headPointer = elt;
4147 nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_HEAD, elt);
4148 push(node);
4151 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushBodyElement(
4152 nsHtml5HtmlAttributes* attributes) {
4153 appendToCurrentNodeAndPushElement(nsHtml5ElementName::ELT_BODY, attributes);
4156 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushBodyElement() {
4157 appendToCurrentNodeAndPushBodyElement(tokenizer->emptyAttributes());
4160 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormElementMayFoster(
4161 nsHtml5HtmlAttributes* attributes) {
4162 nsIContentHandle* elt;
4163 nsHtml5StackNode* current = stack[currentPtr];
4164 if (current->isFosterParenting()) {
4165 elt = createAndInsertFosterParentedElement(
4166 kNameSpaceID_XHTML, nsGkAtoms::form, attributes,
4167 htmlCreator(NS_NewHTMLFormElement));
4168 } else {
4169 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4170 elt = createElement(kNameSpaceID_XHTML, nsGkAtoms::form, attributes,
4171 currentNode, htmlCreator(NS_NewHTMLFormElement));
4172 appendElement(elt, currentNode);
4174 if (!isTemplateContents()) {
4175 formPointer = elt;
4177 nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_FORM, elt);
4178 push(node);
4181 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormattingElementMayFoster(
4182 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4183 nsHtml5HtmlAttributes* clone = attributes->cloneAttributes();
4184 nsIContentHandle* elt;
4185 nsHtml5StackNode* current = stack[currentPtr];
4186 if (current->isFosterParenting()) {
4187 elt = createAndInsertFosterParentedElement(
4188 kNameSpaceID_XHTML, elementName->getName(), attributes,
4189 htmlCreator(elementName->getHtmlCreator()));
4190 } else {
4191 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4192 elt =
4193 createElement(kNameSpaceID_XHTML, elementName->getName(), attributes,
4194 currentNode, htmlCreator(elementName->getHtmlCreator()));
4195 appendElement(elt, currentNode);
4197 nsHtml5StackNode* node = createStackNode(elementName, elt, clone);
4198 push(node);
4199 append(node);
4200 node->retain();
4203 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElement(
4204 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4205 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4206 nsIContentHandle* elt =
4207 createElement(kNameSpaceID_XHTML, elementName->getName(), attributes,
4208 currentNode, htmlCreator(elementName->getHtmlCreator()));
4209 appendElement(elt, currentNode);
4210 if (nsHtml5ElementName::ELT_TEMPLATE == elementName) {
4211 elt = getDocumentFragmentForTemplate(elt);
4213 nsHtml5StackNode* node = createStackNode(elementName, elt);
4214 push(node);
4217 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(
4218 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4219 nsAtom* popName = elementName->getName();
4220 nsIContentHandle* elt;
4221 nsHtml5StackNode* current = stack[currentPtr];
4222 if (current->isFosterParenting()) {
4223 elt = createAndInsertFosterParentedElement(
4224 kNameSpaceID_XHTML, popName, attributes,
4225 htmlCreator(elementName->getHtmlCreator()));
4226 } else {
4227 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4228 elt = createElement(kNameSpaceID_XHTML, popName, attributes, currentNode,
4229 htmlCreator(elementName->getHtmlCreator()));
4230 appendElement(elt, currentNode);
4232 nsHtml5StackNode* node = createStackNode(elementName, elt, popName);
4233 push(node);
4236 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterMathML(
4237 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4238 nsAtom* popName = elementName->getName();
4239 bool markAsHtmlIntegrationPoint = false;
4240 if (nsHtml5ElementName::ELT_ANNOTATION_XML == elementName &&
4241 annotationXmlEncodingPermitsHtml(attributes)) {
4242 markAsHtmlIntegrationPoint = true;
4244 nsIContentHandle* elt;
4245 nsHtml5StackNode* current = stack[currentPtr];
4246 if (current->isFosterParenting()) {
4247 elt = createAndInsertFosterParentedElement(
4248 kNameSpaceID_MathML, popName, attributes, htmlCreator(nullptr));
4249 } else {
4250 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4251 elt = createElement(kNameSpaceID_MathML, popName, attributes, currentNode,
4252 htmlCreator(nullptr));
4253 appendElement(elt, currentNode);
4255 nsHtml5StackNode* node =
4256 createStackNode(elementName, elt, popName, markAsHtmlIntegrationPoint);
4257 push(node);
4260 bool nsHtml5TreeBuilder::annotationXmlEncodingPermitsHtml(
4261 nsHtml5HtmlAttributes* attributes) {
4262 nsHtml5String encoding =
4263 attributes->getValue(nsHtml5AttributeName::ATTR_ENCODING);
4264 if (!encoding) {
4265 return false;
4267 return nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
4268 "application/xhtml+xml", encoding) ||
4269 nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
4270 "text/html", encoding);
4273 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterSVG(
4274 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4275 nsAtom* popName = elementName->getCamelCaseName();
4276 nsIContentHandle* elt;
4277 nsHtml5StackNode* current = stack[currentPtr];
4278 if (current->isFosterParenting()) {
4279 elt = createAndInsertFosterParentedElement(
4280 kNameSpaceID_SVG, popName, attributes,
4281 svgCreator(elementName->getSvgCreator()));
4282 } else {
4283 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4284 elt = createElement(kNameSpaceID_SVG, popName, attributes, currentNode,
4285 svgCreator(elementName->getSvgCreator()));
4286 appendElement(elt, currentNode);
4288 nsHtml5StackNode* node = createStackNode(elementName, popName, elt);
4289 push(node);
4292 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(
4293 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes,
4294 nsIContentHandle* form) {
4295 nsIContentHandle* elt;
4296 nsIContentHandle* formOwner =
4297 !form || fragment || isTemplateContents() ? nullptr : form;
4298 nsHtml5StackNode* current = stack[currentPtr];
4299 if (current->isFosterParenting()) {
4300 elt = createAndInsertFosterParentedElement(
4301 kNameSpaceID_XHTML, elementName->getName(), attributes, formOwner,
4302 htmlCreator(elementName->getHtmlCreator()));
4303 } else {
4304 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4305 elt = createElement(kNameSpaceID_XHTML, elementName->getName(), attributes,
4306 formOwner, currentNode,
4307 htmlCreator(elementName->getHtmlCreator()));
4308 appendElement(elt, currentNode);
4310 nsHtml5StackNode* node = createStackNode(elementName, elt);
4311 push(node);
4314 void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFoster(
4315 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes,
4316 nsIContentHandle* form) {
4317 nsAtom* name = elementName->getName();
4318 nsIContentHandle* elt;
4319 nsIContentHandle* formOwner =
4320 !form || fragment || isTemplateContents() ? nullptr : form;
4321 nsHtml5StackNode* current = stack[currentPtr];
4322 if (current->isFosterParenting()) {
4323 elt = createAndInsertFosterParentedElement(
4324 kNameSpaceID_XHTML, name, attributes, formOwner,
4325 htmlCreator(elementName->getHtmlCreator()));
4326 } else {
4327 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4328 elt =
4329 createElement(kNameSpaceID_XHTML, name, attributes, formOwner,
4330 currentNode, htmlCreator(elementName->getHtmlCreator()));
4331 appendElement(elt, currentNode);
4333 elementPushed(kNameSpaceID_XHTML, name, elt);
4334 elementPopped(kNameSpaceID_XHTML, name, elt);
4337 void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFoster(
4338 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4339 nsAtom* popName = elementName->getName();
4340 nsIContentHandle* elt;
4341 nsHtml5StackNode* current = stack[currentPtr];
4342 if (current->isFosterParenting()) {
4343 elt = createAndInsertFosterParentedElement(
4344 kNameSpaceID_XHTML, popName, attributes,
4345 htmlCreator(elementName->getHtmlCreator()));
4346 } else {
4347 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4348 elt = createElement(kNameSpaceID_XHTML, popName, attributes, currentNode,
4349 htmlCreator(elementName->getHtmlCreator()));
4350 appendElement(elt, currentNode);
4352 elementPushed(kNameSpaceID_XHTML, popName, elt);
4353 elementPopped(kNameSpaceID_XHTML, popName, elt);
4356 void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFosterSVG(
4357 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4358 nsAtom* popName = elementName->getCamelCaseName();
4359 nsIContentHandle* elt;
4360 nsHtml5StackNode* current = stack[currentPtr];
4361 if (current->isFosterParenting()) {
4362 elt = createAndInsertFosterParentedElement(
4363 kNameSpaceID_SVG, popName, attributes,
4364 svgCreator(elementName->getSvgCreator()));
4365 } else {
4366 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4367 elt = createElement(kNameSpaceID_SVG, popName, attributes, currentNode,
4368 svgCreator(elementName->getSvgCreator()));
4369 appendElement(elt, currentNode);
4371 elementPushed(kNameSpaceID_SVG, popName, elt);
4372 elementPopped(kNameSpaceID_SVG, popName, elt);
4375 void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFosterMathML(
4376 nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4377 nsAtom* popName = elementName->getName();
4378 nsIContentHandle* elt;
4379 nsHtml5StackNode* current = stack[currentPtr];
4380 if (current->isFosterParenting()) {
4381 elt = createAndInsertFosterParentedElement(
4382 kNameSpaceID_MathML, popName, attributes, htmlCreator(nullptr));
4383 } else {
4384 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4385 elt = createElement(kNameSpaceID_MathML, popName, attributes, currentNode,
4386 htmlCreator(nullptr));
4387 appendElement(elt, currentNode);
4389 elementPushed(kNameSpaceID_MathML, popName, elt);
4390 elementPopped(kNameSpaceID_MathML, popName, elt);
4393 void nsHtml5TreeBuilder::appendVoidInputToCurrent(
4394 nsHtml5HtmlAttributes* attributes, nsIContentHandle* form) {
4395 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4396 nsIContentHandle* elt =
4397 createElement(kNameSpaceID_XHTML, nsGkAtoms::input, attributes,
4398 !form || fragment || isTemplateContents() ? nullptr : form,
4399 currentNode, htmlCreator(NS_NewHTMLInputElement));
4400 appendElement(elt, currentNode);
4401 elementPushed(kNameSpaceID_XHTML, nsGkAtoms::input, elt);
4402 elementPopped(kNameSpaceID_XHTML, nsGkAtoms::input, elt);
4405 void nsHtml5TreeBuilder::appendVoidFormToCurrent(
4406 nsHtml5HtmlAttributes* attributes) {
4407 nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4408 nsIContentHandle* elt =
4409 createElement(kNameSpaceID_XHTML, nsGkAtoms::form, attributes,
4410 currentNode, htmlCreator(NS_NewHTMLFormElement));
4411 formPointer = elt;
4412 appendElement(elt, currentNode);
4413 elementPushed(kNameSpaceID_XHTML, nsGkAtoms::form, elt);
4414 elementPopped(kNameSpaceID_XHTML, nsGkAtoms::form, elt);
4417 void nsHtml5TreeBuilder::requestSuspension() {
4418 tokenizer->requestSuspension();
4422 bool nsHtml5TreeBuilder::isInForeign() {
4423 return currentPtr >= 0 && stack[currentPtr]->ns != kNameSpaceID_XHTML;
4426 bool nsHtml5TreeBuilder::isInForeignButNotHtmlOrMathTextIntegrationPoint() {
4427 if (currentPtr < 0) {
4428 return false;
4430 return !isSpecialParentInForeign(stack[currentPtr]);
4433 void nsHtml5TreeBuilder::setFragmentContext(nsAtom* context, int32_t ns,
4434 nsIContentHandle* node,
4435 bool quirks) {
4436 this->contextName = context;
4437 this->contextNamespace = ns;
4438 this->contextNode = node;
4439 this->fragment = (!!contextName);
4440 this->quirks = quirks;
4443 nsIContentHandle* nsHtml5TreeBuilder::currentNode() {
4444 return stack[currentPtr]->node;
4447 bool nsHtml5TreeBuilder::isScriptingEnabled() { return scriptingEnabled; }
4449 void nsHtml5TreeBuilder::setScriptingEnabled(bool scriptingEnabled) {
4450 this->scriptingEnabled = scriptingEnabled;
4453 void nsHtml5TreeBuilder::setForceNoQuirks(bool forceNoQuirks) {
4454 this->forceNoQuirks = forceNoQuirks;
4457 void nsHtml5TreeBuilder::setIsSrcdocDocument(bool isSrcdocDocument) {
4458 this->setForceNoQuirks(isSrcdocDocument);
4461 void nsHtml5TreeBuilder::flushCharacters() {
4462 if (charBufferLen > 0) {
4463 if ((mode == IN_TABLE || mode == IN_TABLE_BODY || mode == IN_ROW) &&
4464 charBufferContainsNonWhitespace()) {
4465 errNonSpaceInTable();
4466 reconstructTheActiveFormattingElements();
4467 if (!stack[currentPtr]->isFosterParenting()) {
4468 appendCharacters(currentNode(), charBuffer, 0, charBufferLen);
4469 charBufferLen = 0;
4470 return;
4472 int32_t tablePos = findLastOrRoot(nsHtml5TreeBuilder::TABLE);
4473 int32_t templatePos = findLastOrRoot(nsHtml5TreeBuilder::TEMPLATE);
4474 if (templatePos >= tablePos) {
4475 appendCharacters(stack[templatePos]->node, charBuffer, 0,
4476 charBufferLen);
4477 charBufferLen = 0;
4478 return;
4480 nsHtml5StackNode* tableElt = stack[tablePos];
4481 insertFosterParentedCharacters(charBuffer, 0, charBufferLen,
4482 tableElt->node, stack[tablePos - 1]->node);
4483 charBufferLen = 0;
4484 return;
4486 appendCharacters(currentNode(), charBuffer, 0, charBufferLen);
4487 charBufferLen = 0;
4491 bool nsHtml5TreeBuilder::charBufferContainsNonWhitespace() {
4492 for (int32_t i = 0; i < charBufferLen; i++) {
4493 switch (charBuffer[i]) {
4494 case ' ':
4495 case '\t':
4496 case '\n':
4497 case '\r':
4498 case '\f': {
4499 continue;
4501 default: {
4502 return true;
4506 return false;
4509 nsAHtml5TreeBuilderState* nsHtml5TreeBuilder::newSnapshot() {
4510 jArray<nsHtml5StackNode*, int32_t> listCopy =
4511 jArray<nsHtml5StackNode*, int32_t>::newJArray(listPtr + 1);
4512 for (int32_t i = 0; i < listCopy.length; i++) {
4513 nsHtml5StackNode* node = listOfActiveFormattingElements[i];
4514 if (node) {
4515 nsHtml5StackNode* newNode = new nsHtml5StackNode(-1);
4516 newNode->setValues(node->getFlags(), node->ns, node->name, node->node,
4517 node->popName, node->attributes->cloneAttributes(),
4518 node->getHtmlCreator());
4519 listCopy[i] = newNode;
4520 } else {
4521 listCopy[i] = nullptr;
4524 jArray<nsHtml5StackNode*, int32_t> stackCopy =
4525 jArray<nsHtml5StackNode*, int32_t>::newJArray(currentPtr + 1);
4526 for (int32_t i = 0; i < stackCopy.length; i++) {
4527 nsHtml5StackNode* node = stack[i];
4528 int32_t listIndex = findInListOfActiveFormattingElements(node);
4529 if (listIndex == -1) {
4530 nsHtml5StackNode* newNode = new nsHtml5StackNode(-1);
4531 newNode->setValues(node->getFlags(), node->ns, node->name, node->node,
4532 node->popName, nullptr, node->getHtmlCreator());
4533 stackCopy[i] = newNode;
4534 } else {
4535 stackCopy[i] = listCopy[listIndex];
4536 stackCopy[i]->retain();
4539 jArray<int32_t, int32_t> templateModeStackCopy =
4540 jArray<int32_t, int32_t>::newJArray(templateModePtr + 1);
4541 nsHtml5ArrayCopy::arraycopy(templateModeStack, templateModeStackCopy,
4542 templateModeStackCopy.length);
4543 return new nsHtml5StateSnapshot(stackCopy, listCopy, templateModeStackCopy,
4544 formPointer, headPointer, mode, originalMode,
4545 framesetOk, needToDropLF, quirks);
4548 bool nsHtml5TreeBuilder::snapshotMatches(nsAHtml5TreeBuilderState* snapshot) {
4549 jArray<nsHtml5StackNode*, int32_t> stackCopy = snapshot->getStack();
4550 int32_t stackLen = snapshot->getStackLength();
4551 jArray<nsHtml5StackNode*, int32_t> listCopy =
4552 snapshot->getListOfActiveFormattingElements();
4553 int32_t listLen = snapshot->getListOfActiveFormattingElementsLength();
4554 jArray<int32_t, int32_t> templateModeStackCopy =
4555 snapshot->getTemplateModeStack();
4556 int32_t templateModeStackLen = snapshot->getTemplateModeStackLength();
4557 if (stackLen != currentPtr + 1 || listLen != listPtr + 1 ||
4558 templateModeStackLen != templateModePtr + 1 ||
4559 formPointer != snapshot->getFormPointer() ||
4560 headPointer != snapshot->getHeadPointer() ||
4561 mode != snapshot->getMode() ||
4562 originalMode != snapshot->getOriginalMode() ||
4563 framesetOk != snapshot->isFramesetOk() ||
4564 needToDropLF != snapshot->isNeedToDropLF() ||
4565 quirks != snapshot->isQuirks()) {
4566 return false;
4568 for (int32_t i = listLen - 1; i >= 0; i--) {
4569 if (!listCopy[i] && !listOfActiveFormattingElements[i]) {
4570 continue;
4571 } else if (!listCopy[i] || !listOfActiveFormattingElements[i]) {
4572 return false;
4574 if (listCopy[i]->node != listOfActiveFormattingElements[i]->node) {
4575 return false;
4578 for (int32_t i = stackLen - 1; i >= 0; i--) {
4579 if (stackCopy[i]->node != stack[i]->node) {
4580 return false;
4583 for (int32_t i = templateModeStackLen - 1; i >= 0; i--) {
4584 if (templateModeStackCopy[i] != templateModeStack[i]) {
4585 return false;
4588 return true;
4591 void nsHtml5TreeBuilder::loadState(nsAHtml5TreeBuilderState* snapshot) {
4592 mCurrentHtmlScriptCannotDocumentWriteOrBlock = false;
4593 jArray<nsHtml5StackNode*, int32_t> stackCopy = snapshot->getStack();
4594 int32_t stackLen = snapshot->getStackLength();
4595 jArray<nsHtml5StackNode*, int32_t> listCopy =
4596 snapshot->getListOfActiveFormattingElements();
4597 int32_t listLen = snapshot->getListOfActiveFormattingElementsLength();
4598 jArray<int32_t, int32_t> templateModeStackCopy =
4599 snapshot->getTemplateModeStack();
4600 int32_t templateModeStackLen = snapshot->getTemplateModeStackLength();
4601 for (int32_t i = 0; i <= listPtr; i++) {
4602 if (listOfActiveFormattingElements[i]) {
4603 listOfActiveFormattingElements[i]->release(this);
4606 if (listOfActiveFormattingElements.length < listLen) {
4607 listOfActiveFormattingElements =
4608 jArray<nsHtml5StackNode*, int32_t>::newJArray(listLen);
4610 listPtr = listLen - 1;
4611 for (int32_t i = 0; i <= currentPtr; i++) {
4612 stack[i]->release(this);
4614 if (stack.length < stackLen) {
4615 stack = jArray<nsHtml5StackNode*, int32_t>::newJArray(stackLen);
4617 currentPtr = stackLen - 1;
4618 if (templateModeStack.length < templateModeStackLen) {
4619 templateModeStack =
4620 jArray<int32_t, int32_t>::newJArray(templateModeStackLen);
4622 templateModePtr = templateModeStackLen - 1;
4623 for (int32_t i = 0; i < listLen; i++) {
4624 nsHtml5StackNode* node = listCopy[i];
4625 if (node) {
4626 nsHtml5StackNode* newNode = createStackNode(
4627 node->getFlags(), node->ns, node->name, node->node, node->popName,
4628 node->attributes->cloneAttributes(), node->getHtmlCreator());
4629 listOfActiveFormattingElements[i] = newNode;
4630 } else {
4631 listOfActiveFormattingElements[i] = nullptr;
4634 for (int32_t i = 0; i < stackLen; i++) {
4635 nsHtml5StackNode* node = stackCopy[i];
4636 int32_t listIndex = findInArray(node, listCopy);
4637 if (listIndex == -1) {
4638 nsHtml5StackNode* newNode =
4639 createStackNode(node->getFlags(), node->ns, node->name, node->node,
4640 node->popName, nullptr, node->getHtmlCreator());
4641 stack[i] = newNode;
4642 } else {
4643 stack[i] = listOfActiveFormattingElements[listIndex];
4644 stack[i]->retain();
4647 nsHtml5ArrayCopy::arraycopy(templateModeStackCopy, templateModeStack,
4648 templateModeStackLen);
4649 formPointer = snapshot->getFormPointer();
4650 headPointer = snapshot->getHeadPointer();
4651 mode = snapshot->getMode();
4652 originalMode = snapshot->getOriginalMode();
4653 framesetOk = snapshot->isFramesetOk();
4654 needToDropLF = snapshot->isNeedToDropLF();
4655 quirks = snapshot->isQuirks();
4658 int32_t nsHtml5TreeBuilder::findInArray(
4659 nsHtml5StackNode* node, jArray<nsHtml5StackNode*, int32_t> arr) {
4660 for (int32_t i = listPtr; i >= 0; i--) {
4661 if (node == arr[i]) {
4662 return i;
4665 return -1;
4668 nsIContentHandle* nsHtml5TreeBuilder::nodeFromStackWithBlinkCompat(
4669 int32_t stackPos) {
4670 if (stackPos > 511) {
4671 errDeepTree();
4672 return stack[511]->node;
4674 return stack[stackPos]->node;
4677 nsIContentHandle* nsHtml5TreeBuilder::getFormPointer() { return formPointer; }
4679 nsIContentHandle* nsHtml5TreeBuilder::getHeadPointer() { return headPointer; }
4681 jArray<nsHtml5StackNode*, int32_t>
4682 nsHtml5TreeBuilder::getListOfActiveFormattingElements() {
4683 return listOfActiveFormattingElements;
4686 jArray<nsHtml5StackNode*, int32_t> nsHtml5TreeBuilder::getStack() {
4687 return stack;
4690 jArray<int32_t, int32_t> nsHtml5TreeBuilder::getTemplateModeStack() {
4691 return templateModeStack;
4694 int32_t nsHtml5TreeBuilder::getMode() { return mode; }
4696 int32_t nsHtml5TreeBuilder::getOriginalMode() { return originalMode; }
4698 bool nsHtml5TreeBuilder::isFramesetOk() { return framesetOk; }
4700 bool nsHtml5TreeBuilder::isNeedToDropLF() { return needToDropLF; }
4702 bool nsHtml5TreeBuilder::isQuirks() { return quirks; }
4704 int32_t nsHtml5TreeBuilder::getListOfActiveFormattingElementsLength() {
4705 return listPtr + 1;
4708 int32_t nsHtml5TreeBuilder::getStackLength() { return currentPtr + 1; }
4710 int32_t nsHtml5TreeBuilder::getTemplateModeStackLength() {
4711 return templateModePtr + 1;
4714 void nsHtml5TreeBuilder::initializeStatics() {}
4716 void nsHtml5TreeBuilder::releaseStatics() {}
4718 #include "nsHtml5TreeBuilderCppSupplement.h"