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.
6  *
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:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
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.
24  */
25 
26 /*
27  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
28  * Please edit TreeBuilder.java instead and regenerate.
29  */
30 
31 #define nsHtml5TreeBuilder_cpp__
32 
33 #include "jArray.h"
34 #include "mozilla/ImportScanner.h"
35 #include "mozilla/Likely.h"
36 #include "nsAHtml5TreeBuilderState.h"
37 #include "nsAtom.h"
38 #include "nsContentUtils.h"
39 #include "nsGkAtoms.h"
40 #include "nsHtml5ArrayCopy.h"
41 #include "nsHtml5AtomTable.h"
42 #include "nsHtml5DocumentMode.h"
43 #include "nsHtml5Highlighter.h"
44 #include "nsHtml5OplessBuilder.h"
45 #include "nsHtml5Parser.h"
46 #include "nsHtml5PlainTextUtils.h"
47 #include "nsHtml5StackNode.h"
48 #include "nsHtml5StateSnapshot.h"
49 #include "nsHtml5StreamParser.h"
50 #include "nsHtml5String.h"
51 #include "nsHtml5TreeOperation.h"
52 #include "nsHtml5TreeOpExecutor.h"
53 #include "nsHtml5ViewSourceUtils.h"
54 #include "nsIContent.h"
55 #include "nsIContentHandle.h"
56 #include "nsNameSpaceManager.h"
57 #include "nsTraceRefcnt.h"
58 
59 #include "nsHtml5AttributeName.h"
60 #include "nsHtml5ElementName.h"
61 #include "nsHtml5Tokenizer.h"
62 #include "nsHtml5StackNode.h"
63 #include "nsHtml5UTF16Buffer.h"
64 #include "nsHtml5StateSnapshot.h"
65 #include "nsHtml5Portability.h"
66 
67 #include "nsHtml5TreeBuilder.h"
68 
69 char16_t nsHtml5TreeBuilder::REPLACEMENT_CHARACTER[] = {0xfffd};
70 static const char* const QUIRKY_PUBLIC_IDS_DATA[] = {
71     "+//silmaril//dtd html pro v0r11 19970101//",
72     "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
73     "-//as//dtd html 3.0 aswedit + extensions//",
74     "-//ietf//dtd html 2.0 level 1//",
75     "-//ietf//dtd html 2.0 level 2//",
76     "-//ietf//dtd html 2.0 strict level 1//",
77     "-//ietf//dtd html 2.0 strict level 2//",
78     "-//ietf//dtd html 2.0 strict//",
79     "-//ietf//dtd html 2.0//",
80     "-//ietf//dtd html 2.1e//",
81     "-//ietf//dtd html 3.0//",
82     "-//ietf//dtd html 3.2 final//",
83     "-//ietf//dtd html 3.2//",
84     "-//ietf//dtd html 3//",
85     "-//ietf//dtd html level 0//",
86     "-//ietf//dtd html level 1//",
87     "-//ietf//dtd html level 2//",
88     "-//ietf//dtd html level 3//",
89     "-//ietf//dtd html strict level 0//",
90     "-//ietf//dtd html strict level 1//",
91     "-//ietf//dtd html strict level 2//",
92     "-//ietf//dtd html strict level 3//",
93     "-//ietf//dtd html strict//",
94     "-//ietf//dtd html//",
95     "-//metrius//dtd metrius presentational//",
96     "-//microsoft//dtd internet explorer 2.0 html strict//",
97     "-//microsoft//dtd internet explorer 2.0 html//",
98     "-//microsoft//dtd internet explorer 2.0 tables//",
99     "-//microsoft//dtd internet explorer 3.0 html strict//",
100     "-//microsoft//dtd internet explorer 3.0 html//",
101     "-//microsoft//dtd internet explorer 3.0 tables//",
102     "-//netscape comm. corp.//dtd html//",
103     "-//netscape comm. corp.//dtd strict html//",
104     "-//o'reilly and associates//dtd html 2.0//",
105     "-//o'reilly and associates//dtd html extended 1.0//",
106     "-//o'reilly and associates//dtd html extended relaxed 1.0//",
107     "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html "
108     "4.0//",
109     "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
110     "-//spyglass//dtd html 2.0 extended//",
111     "-//sq//dtd html 2.0 hotmetal + extensions//",
112     "-//sun microsystems corp.//dtd hotjava html//",
113     "-//sun microsystems corp.//dtd hotjava strict html//",
114     "-//w3c//dtd html 3 1995-03-24//",
115     "-//w3c//dtd html 3.2 draft//",
116     "-//w3c//dtd html 3.2 final//",
117     "-//w3c//dtd html 3.2//",
118     "-//w3c//dtd html 3.2s draft//",
119     "-//w3c//dtd html 4.0 frameset//",
120     "-//w3c//dtd html 4.0 transitional//",
121     "-//w3c//dtd html experimental 19960712//",
122     "-//w3c//dtd html experimental 970421//",
123     "-//w3c//dtd w3 html//",
124     "-//w3o//dtd w3 html 3.0//",
125     "-//webtechs//dtd mozilla html 2.0//",
126     "-//webtechs//dtd mozilla html//"};
127 staticJArray<const char*, int32_t> nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS = {
128     QUIRKY_PUBLIC_IDS_DATA, MOZ_ARRAY_LENGTH(QUIRKY_PUBLIC_IDS_DATA)};
startTokenization(nsHtml5Tokenizer * self)129 void nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self) {
130   tokenizer = self;
131   stackNodes = jArray<nsHtml5StackNode*, int32_t>::newJArray(64);
132   stack = jArray<nsHtml5StackNode*, int32_t>::newJArray(64);
133   templateModeStack = jArray<int32_t, int32_t>::newJArray(64);
134   listOfActiveFormattingElements =
135       jArray<nsHtml5StackNode*, int32_t>::newJArray(64);
136   needToDropLF = false;
137   originalMode = INITIAL;
138   templateModePtr = -1;
139   stackNodesIdx = 0;
140   numStackNodes = 0;
141   currentPtr = -1;
142   listPtr = -1;
143   formPointer = nullptr;
144   headPointer = nullptr;
145   start(fragment);
146   charBufferLen = 0;
147   charBuffer = nullptr;
148   framesetOk = true;
149   if (fragment) {
150     nsIContentHandle* elt;
151     if (contextNode) {
152       elt = contextNode;
153     } else {
154       elt = createHtmlElementSetAsRoot(tokenizer->emptyAttributes());
155     }
156     if (contextNamespace == kNameSpaceID_SVG) {
157       nsHtml5ElementName* elementName = nsHtml5ElementName::ELT_SVG;
158       if (nsGkAtoms::title == contextName || nsGkAtoms::desc == contextName ||
159           nsGkAtoms::foreignObject == contextName) {
160         elementName = nsHtml5ElementName::ELT_FOREIGNOBJECT;
161       }
162       nsHtml5StackNode* node =
163           createStackNode(elementName, elementName->getCamelCaseName(), elt);
164       currentPtr++;
165       stack[currentPtr] = node;
166       tokenizer->setState(nsHtml5Tokenizer::DATA);
167       mode = FRAMESET_OK;
168     } else if (contextNamespace == kNameSpaceID_MathML) {
169       nsHtml5ElementName* elementName = nsHtml5ElementName::ELT_MATH;
170       if (nsGkAtoms::mi_ == contextName || nsGkAtoms::mo_ == contextName ||
171           nsGkAtoms::mn_ == contextName || nsGkAtoms::ms_ == contextName ||
172           nsGkAtoms::mtext_ == contextName) {
173         elementName = nsHtml5ElementName::ELT_MTEXT;
174       } else if (nsGkAtoms::annotation_xml_ == contextName) {
175         elementName = nsHtml5ElementName::ELT_ANNOTATION_XML;
176       }
177       nsHtml5StackNode* node =
178           createStackNode(elementName, elt, elementName->getName(), false);
179       currentPtr++;
180       stack[currentPtr] = node;
181       tokenizer->setState(nsHtml5Tokenizer::DATA);
182       mode = FRAMESET_OK;
183     } else {
184       nsHtml5StackNode* node =
185           createStackNode(nsHtml5ElementName::ELT_HTML, elt);
186       currentPtr++;
187       stack[currentPtr] = node;
188       if (nsGkAtoms::_template == contextName) {
189         pushTemplateMode(IN_TEMPLATE);
190       }
191       resetTheInsertionMode();
192       formPointer = getFormPointerForContext(contextNode);
193       if (nsGkAtoms::title == contextName ||
194           nsGkAtoms::textarea == contextName) {
195         tokenizer->setState(nsHtml5Tokenizer::RCDATA);
196       } else if (nsGkAtoms::style == contextName ||
197                  nsGkAtoms::xmp == contextName ||
198                  nsGkAtoms::iframe == contextName ||
199                  nsGkAtoms::noembed == contextName ||
200                  nsGkAtoms::noframes == contextName ||
201                  (scriptingEnabled && nsGkAtoms::noscript == contextName)) {
202         tokenizer->setState(nsHtml5Tokenizer::RAWTEXT);
203       } else if (nsGkAtoms::plaintext == contextName) {
204         tokenizer->setState(nsHtml5Tokenizer::PLAINTEXT);
205       } else if (nsGkAtoms::script == contextName) {
206         tokenizer->setState(nsHtml5Tokenizer::SCRIPT_DATA);
207       } else {
208         tokenizer->setState(nsHtml5Tokenizer::DATA);
209       }
210     }
211   } else {
212     mode = INITIAL;
213     if (tokenizer->isViewingXmlSource()) {
214       nsIContentHandle* elt = createElement(
215           kNameSpaceID_SVG, nsGkAtoms::svg, tokenizer->emptyAttributes(),
216           nullptr, svgCreator(NS_NewSVGSVGElement));
217       nsHtml5StackNode* node =
218           createStackNode(nsHtml5ElementName::ELT_SVG, nsGkAtoms::svg, elt);
219       currentPtr++;
220       stack[currentPtr] = node;
221     }
222   }
223 }
224 
doctype(nsAtom * name,nsHtml5String publicIdentifier,nsHtml5String systemIdentifier,bool forceQuirks)225 void nsHtml5TreeBuilder::doctype(nsAtom* name, nsHtml5String publicIdentifier,
226                                  nsHtml5String systemIdentifier,
227                                  bool forceQuirks) {
228   needToDropLF = false;
229   if (!isInForeign() && mode == INITIAL) {
230     nsHtml5String emptyString = nsHtml5Portability::newEmptyString();
231     appendDoctypeToDocument(!name ? nsGkAtoms::_empty : name,
232                             !publicIdentifier ? emptyString : publicIdentifier,
233                             !systemIdentifier ? emptyString : systemIdentifier);
234     emptyString.Release();
235     if (isQuirky(name, publicIdentifier, systemIdentifier, forceQuirks)) {
236       errQuirkyDoctype();
237       documentModeInternal(QUIRKS_MODE, publicIdentifier, systemIdentifier);
238     } else if (isAlmostStandards(publicIdentifier, systemIdentifier)) {
239       errAlmostStandardsDoctype();
240       documentModeInternal(ALMOST_STANDARDS_MODE, publicIdentifier,
241                            systemIdentifier);
242     } else {
243       documentModeInternal(STANDARDS_MODE, publicIdentifier, systemIdentifier);
244     }
245     mode = BEFORE_HTML;
246     return;
247   }
248   errStrayDoctype();
249   return;
250 }
251 
comment(char16_t * buf,int32_t start,int32_t length)252 void nsHtml5TreeBuilder::comment(char16_t* buf, int32_t start, int32_t length) {
253   needToDropLF = false;
254   if (!isInForeign()) {
255     switch (mode) {
256       case INITIAL:
257       case BEFORE_HTML:
258       case AFTER_AFTER_BODY:
259       case AFTER_AFTER_FRAMESET: {
260         appendCommentToDocument(buf, start, length);
261         return;
262       }
263       case AFTER_BODY: {
264         flushCharacters();
265         appendComment(stack[0]->node, buf, start, length);
266         return;
267       }
268       default: {
269         break;
270       }
271     }
272   }
273   flushCharacters();
274   appendComment(stack[currentPtr]->node, buf, start, length);
275   return;
276 }
277 
characters(const char16_t * buf,int32_t start,int32_t length)278 void nsHtml5TreeBuilder::characters(const char16_t* buf, int32_t start,
279                                     int32_t length) {
280   if (tokenizer->isViewingXmlSource()) {
281     return;
282   }
283   if (needToDropLF) {
284     needToDropLF = false;
285     if (buf[start] == '\n') {
286       start++;
287       length--;
288       if (!length) {
289         return;
290       }
291     }
292   }
293   switch (mode) {
294     case IN_BODY:
295     case IN_CELL:
296     case IN_CAPTION: {
297       if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
298         reconstructTheActiveFormattingElements();
299       }
300       [[fallthrough]];
301     }
302     case TEXT: {
303       accumulateCharacters(buf, start, length);
304       return;
305     }
306     case IN_TABLE:
307     case IN_TABLE_BODY:
308     case IN_ROW: {
309       accumulateCharactersForced(buf, start, length);
310       return;
311     }
312     default: {
313       int32_t end = start + length;
314       for (int32_t i = start; i < end; i++) {
315         switch (buf[i]) {
316           case ' ':
317           case '\t':
318           case '\n':
319           case '\r':
320           case '\f': {
321             switch (mode) {
322               case INITIAL:
323               case BEFORE_HTML:
324               case BEFORE_HEAD: {
325                 start = i + 1;
326                 continue;
327               }
328               case IN_HEAD:
329               case IN_HEAD_NOSCRIPT:
330               case AFTER_HEAD:
331               case IN_COLUMN_GROUP:
332               case IN_FRAMESET:
333               case AFTER_FRAMESET: {
334                 continue;
335               }
336               case FRAMESET_OK:
337               case IN_TEMPLATE:
338               case IN_BODY:
339               case IN_CELL:
340               case IN_CAPTION: {
341                 if (start < i) {
342                   accumulateCharacters(buf, start, i - start);
343                   start = i;
344                 }
345                 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
346                   flushCharacters();
347                   reconstructTheActiveFormattingElements();
348                 }
349                 NS_HTML5_BREAK(charactersloop);
350               }
351               case IN_SELECT:
352               case IN_SELECT_IN_TABLE: {
353                 NS_HTML5_BREAK(charactersloop);
354               }
355               case IN_TABLE:
356               case IN_TABLE_BODY:
357               case IN_ROW: {
358                 accumulateCharactersForced(buf, i, 1);
359                 start = i + 1;
360                 continue;
361               }
362               case AFTER_BODY:
363               case AFTER_AFTER_BODY:
364               case AFTER_AFTER_FRAMESET: {
365                 if (start < i) {
366                   accumulateCharacters(buf, start, i - start);
367                   start = i;
368                 }
369                 flushCharacters();
370                 reconstructTheActiveFormattingElements();
371                 continue;
372               }
373             }
374             MOZ_FALLTHROUGH_ASSERT();
375           }
376           default: {
377             switch (mode) {
378               case INITIAL: {
379                 documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
380                 mode = BEFORE_HTML;
381                 i--;
382                 continue;
383               }
384               case BEFORE_HTML: {
385                 appendHtmlElementToDocumentAndPush();
386                 mode = BEFORE_HEAD;
387                 i--;
388                 continue;
389               }
390               case BEFORE_HEAD: {
391                 if (start < i) {
392                   accumulateCharacters(buf, start, i - start);
393                   start = i;
394                 }
395                 flushCharacters();
396                 appendToCurrentNodeAndPushHeadElement(
397                     nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
398                 mode = IN_HEAD;
399                 i--;
400                 continue;
401               }
402               case IN_HEAD: {
403                 if (start < i) {
404                   accumulateCharacters(buf, start, i - start);
405                   start = i;
406                 }
407                 flushCharacters();
408                 pop();
409                 mode = AFTER_HEAD;
410                 i--;
411                 continue;
412               }
413               case IN_HEAD_NOSCRIPT: {
414                 if (start < i) {
415                   accumulateCharacters(buf, start, i - start);
416                   start = i;
417                 }
418                 errNonSpaceInNoscriptInHead();
419                 flushCharacters();
420                 pop();
421                 mode = IN_HEAD;
422                 i--;
423                 continue;
424               }
425               case AFTER_HEAD: {
426                 if (start < i) {
427                   accumulateCharacters(buf, start, i - start);
428                   start = i;
429                 }
430                 flushCharacters();
431                 appendToCurrentNodeAndPushBodyElement();
432                 mode = FRAMESET_OK;
433                 i--;
434                 continue;
435               }
436               case FRAMESET_OK: {
437                 framesetOk = false;
438                 mode = IN_BODY;
439                 i--;
440                 continue;
441               }
442               case IN_TEMPLATE:
443               case IN_BODY:
444               case IN_CELL:
445               case IN_CAPTION: {
446                 if (start < i) {
447                   accumulateCharacters(buf, start, i - start);
448                   start = i;
449                 }
450                 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
451                   flushCharacters();
452                   reconstructTheActiveFormattingElements();
453                 }
454                 NS_HTML5_BREAK(charactersloop);
455               }
456               case IN_TABLE:
457               case IN_TABLE_BODY:
458               case IN_ROW: {
459                 accumulateCharactersForced(buf, i, 1);
460                 start = i + 1;
461                 continue;
462               }
463               case IN_COLUMN_GROUP: {
464                 if (start < i) {
465                   accumulateCharacters(buf, start, i - start);
466                   start = i;
467                 }
468                 if (!currentPtr || stack[currentPtr]->getGroup() ==
469                                        nsHtml5TreeBuilder::TEMPLATE) {
470                   errNonSpaceInColgroupInFragment();
471                   start = i + 1;
472                   continue;
473                 }
474                 flushCharacters();
475                 pop();
476                 mode = IN_TABLE;
477                 i--;
478                 continue;
479               }
480               case IN_SELECT:
481               case IN_SELECT_IN_TABLE: {
482                 NS_HTML5_BREAK(charactersloop);
483               }
484               case AFTER_BODY: {
485                 errNonSpaceAfterBody();
486 
487                 mode = framesetOk ? FRAMESET_OK : IN_BODY;
488                 i--;
489                 continue;
490               }
491               case IN_FRAMESET: {
492                 if (start < i) {
493                   accumulateCharacters(buf, start, i - start);
494                 }
495                 errNonSpaceInFrameset();
496                 start = i + 1;
497                 continue;
498               }
499               case AFTER_FRAMESET: {
500                 if (start < i) {
501                   accumulateCharacters(buf, start, i - start);
502                 }
503                 errNonSpaceAfterFrameset();
504                 start = i + 1;
505                 continue;
506               }
507               case AFTER_AFTER_BODY: {
508                 errNonSpaceInTrailer();
509                 mode = framesetOk ? FRAMESET_OK : IN_BODY;
510                 i--;
511                 continue;
512               }
513               case AFTER_AFTER_FRAMESET: {
514                 if (start < i) {
515                   accumulateCharacters(buf, start, i - start);
516                 }
517                 errNonSpaceInTrailer();
518                 start = i + 1;
519                 continue;
520               }
521             }
522           }
523         }
524       }
525     charactersloop_end:;
526       if (start < end) {
527         accumulateCharacters(buf, start, end - start);
528       }
529     }
530   }
531 }
532 
zeroOriginatingReplacementCharacter()533 void nsHtml5TreeBuilder::zeroOriginatingReplacementCharacter() {
534   if (mode == TEXT) {
535     accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1);
536     return;
537   }
538   if (currentPtr >= 0) {
539     if (isSpecialParentInForeign(stack[currentPtr])) {
540       return;
541     }
542     accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1);
543   }
544 }
545 
zeroOrReplacementCharacter()546 void nsHtml5TreeBuilder::zeroOrReplacementCharacter() {
547   zeroOriginatingReplacementCharacter();
548 }
549 
eof()550 void nsHtml5TreeBuilder::eof() {
551   flushCharacters();
552   for (;;) {
553     switch (mode) {
554       case INITIAL: {
555         documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
556         mode = BEFORE_HTML;
557         continue;
558       }
559       case BEFORE_HTML: {
560         appendHtmlElementToDocumentAndPush();
561         mode = BEFORE_HEAD;
562         continue;
563       }
564       case BEFORE_HEAD: {
565         appendToCurrentNodeAndPushHeadElement(
566             nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
567         mode = IN_HEAD;
568         continue;
569       }
570       case IN_HEAD: {
571         while (currentPtr > 0) {
572           popOnEof();
573         }
574         mode = AFTER_HEAD;
575         continue;
576       }
577       case IN_HEAD_NOSCRIPT: {
578         while (currentPtr > 1) {
579           popOnEof();
580         }
581         mode = IN_HEAD;
582         continue;
583       }
584       case AFTER_HEAD: {
585         appendToCurrentNodeAndPushBodyElement();
586         mode = IN_BODY;
587         continue;
588       }
589       case IN_TABLE_BODY:
590       case IN_ROW:
591       case IN_TABLE:
592       case IN_SELECT_IN_TABLE:
593       case IN_SELECT:
594       case IN_COLUMN_GROUP:
595       case FRAMESET_OK:
596       case IN_CAPTION:
597       case IN_CELL:
598       case IN_BODY: {
599         if (isTemplateModeStackEmpty()) {
600           NS_HTML5_BREAK(eofloop);
601         }
602         [[fallthrough]];
603       }
604       case IN_TEMPLATE: {
605         int32_t eltPos = findLast(nsGkAtoms::_template);
606         if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
607           MOZ_ASSERT(fragment);
608           NS_HTML5_BREAK(eofloop);
609         }
610         if (MOZ_UNLIKELY(mViewSource)) {
611           errListUnclosedStartTags(0);
612         }
613         while (currentPtr >= eltPos) {
614           pop();
615         }
616         clearTheListOfActiveFormattingElementsUpToTheLastMarker();
617         popTemplateMode();
618         resetTheInsertionMode();
619         continue;
620       }
621       case TEXT: {
622         if (originalMode == AFTER_HEAD) {
623           popOnEof();
624         }
625         popOnEof();
626         mode = originalMode;
627         continue;
628       }
629       case IN_FRAMESET: {
630         NS_HTML5_BREAK(eofloop);
631       }
632       case AFTER_BODY:
633       case AFTER_FRAMESET:
634       case AFTER_AFTER_BODY:
635       case AFTER_AFTER_FRAMESET:
636       default: {
637         NS_HTML5_BREAK(eofloop);
638       }
639     }
640   }
641 eofloop_end:;
642   while (currentPtr > 0) {
643     popOnEof();
644   }
645   if (!fragment) {
646     popOnEof();
647   }
648 }
649 
endTokenization()650 void nsHtml5TreeBuilder::endTokenization() {
651   formPointer = nullptr;
652   headPointer = nullptr;
653   contextName = nullptr;
654   contextNode = nullptr;
655   templateModeStack = nullptr;
656   if (stack) {
657     while (currentPtr > -1) {
658       stack[currentPtr]->release(this);
659       currentPtr--;
660     }
661     stack = nullptr;
662   }
663   if (listOfActiveFormattingElements) {
664     while (listPtr > -1) {
665       if (listOfActiveFormattingElements[listPtr]) {
666         listOfActiveFormattingElements[listPtr]->release(this);
667       }
668       listPtr--;
669     }
670     listOfActiveFormattingElements = nullptr;
671   }
672   if (stackNodes) {
673     for (int32_t i = 0; i < numStackNodes; i++) {
674       MOZ_ASSERT(stackNodes[i]->isUnused());
675       delete stackNodes[i];
676     }
677     numStackNodes = 0;
678     stackNodesIdx = 0;
679     stackNodes = nullptr;
680   }
681   charBuffer = nullptr;
682   end();
683 }
684 
startTag(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes,bool selfClosing)685 void nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName,
686                                   nsHtml5HtmlAttributes* attributes,
687                                   bool selfClosing) {
688   flushCharacters();
689   int32_t eltPos;
690   needToDropLF = false;
691 starttagloop:
692   for (;;) {
693     int32_t group = elementName->getGroup();
694     nsAtom* name = elementName->getName();
695     if (isInForeign()) {
696       nsHtml5StackNode* currentNode = stack[currentPtr];
697       int32_t currNs = currentNode->ns;
698       if (!(currentNode->isHtmlIntegrationPoint() ||
699             (currNs == kNameSpaceID_MathML &&
700              ((currentNode->getGroup() == MI_MO_MN_MS_MTEXT &&
701                group != MGLYPH_OR_MALIGNMARK) ||
702               (currentNode->getGroup() == ANNOTATION_XML && group == SVG))))) {
703         switch (group) {
704           case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
705           case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
706           case BODY:
707           case BR:
708           case RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR:
709           case DD_OR_DT:
710           case UL_OR_OL_OR_DL:
711           case EMBED:
712           case IMG:
713           case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6:
714           case HEAD:
715           case HR:
716           case LI:
717           case META:
718           case NOBR:
719           case P:
720           case PRE_OR_LISTING:
721           case TABLE:
722           case FONT: {
723             if (!(group == FONT &&
724                   !(attributes->contains(nsHtml5AttributeName::ATTR_COLOR) ||
725                     attributes->contains(nsHtml5AttributeName::ATTR_FACE) ||
726                     attributes->contains(nsHtml5AttributeName::ATTR_SIZE)))) {
727               errHtmlStartTagInForeignContext(name);
728               if (!fragment) {
729                 while (!isSpecialParentInForeign(stack[currentPtr])) {
730                   popForeign(-1, -1);
731                 }
732                 NS_HTML5_CONTINUE(starttagloop);
733               }
734             }
735             [[fallthrough]];
736           }
737           default: {
738             if (kNameSpaceID_SVG == currNs) {
739               attributes->adjustForSvg();
740               if (selfClosing) {
741                 appendVoidElementToCurrentMayFosterSVG(elementName, attributes);
742                 selfClosing = false;
743               } else {
744                 appendToCurrentNodeAndPushElementMayFosterSVG(elementName,
745                                                               attributes);
746               }
747               attributes = nullptr;
748               NS_HTML5_BREAK(starttagloop);
749             } else {
750               attributes->adjustForMath();
751               if (selfClosing) {
752                 appendVoidElementToCurrentMayFosterMathML(elementName,
753                                                           attributes);
754                 selfClosing = false;
755               } else {
756                 appendToCurrentNodeAndPushElementMayFosterMathML(elementName,
757                                                                  attributes);
758               }
759               attributes = nullptr;
760               NS_HTML5_BREAK(starttagloop);
761             }
762           }
763         }
764       }
765     }
766     switch (mode) {
767       case IN_TEMPLATE: {
768         switch (group) {
769           case COL: {
770             popTemplateMode();
771             pushTemplateMode(IN_COLUMN_GROUP);
772             mode = IN_COLUMN_GROUP;
773             continue;
774           }
775           case CAPTION:
776           case COLGROUP:
777           case TBODY_OR_THEAD_OR_TFOOT: {
778             popTemplateMode();
779             pushTemplateMode(IN_TABLE);
780             mode = IN_TABLE;
781             continue;
782           }
783           case TR: {
784             popTemplateMode();
785             pushTemplateMode(IN_TABLE_BODY);
786             mode = IN_TABLE_BODY;
787             continue;
788           }
789           case TD_OR_TH: {
790             popTemplateMode();
791             pushTemplateMode(IN_ROW);
792             mode = IN_ROW;
793             continue;
794           }
795           case META: {
796             checkMetaCharset(attributes);
797             appendVoidElementToCurrentMayFoster(elementName, attributes);
798             selfClosing = false;
799             attributes = nullptr;
800             NS_HTML5_BREAK(starttagloop);
801           }
802           case TITLE: {
803             startTagTitleInHead(elementName, attributes);
804             attributes = nullptr;
805             NS_HTML5_BREAK(starttagloop);
806           }
807           case BASE:
808           case LINK_OR_BASEFONT_OR_BGSOUND: {
809             appendVoidElementToCurrentMayFoster(elementName, attributes);
810             selfClosing = false;
811             attributes = nullptr;
812             NS_HTML5_BREAK(starttagloop);
813           }
814           case SCRIPT: {
815             startTagScriptInHead(elementName, attributes);
816             attributes = nullptr;
817             NS_HTML5_BREAK(starttagloop);
818           }
819           case NOFRAMES:
820           case STYLE: {
821             startTagGenericRawText(elementName, attributes);
822             attributes = nullptr;
823             NS_HTML5_BREAK(starttagloop);
824           }
825           case TEMPLATE: {
826             startTagTemplateInHead(elementName, attributes);
827             attributes = nullptr;
828             NS_HTML5_BREAK(starttagloop);
829           }
830           default: {
831             popTemplateMode();
832             pushTemplateMode(IN_BODY);
833             mode = IN_BODY;
834             continue;
835           }
836         }
837       }
838       case IN_ROW: {
839         switch (group) {
840           case TD_OR_TH: {
841             clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TR));
842             appendToCurrentNodeAndPushElement(elementName, attributes);
843             mode = IN_CELL;
844             insertMarker();
845             attributes = nullptr;
846             NS_HTML5_BREAK(starttagloop);
847           }
848           case CAPTION:
849           case COL:
850           case COLGROUP:
851           case TBODY_OR_THEAD_OR_TFOOT:
852           case TR: {
853             eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
854             if (!eltPos) {
855               MOZ_ASSERT(fragment || isTemplateContents());
856               errNoTableRowToClose();
857               NS_HTML5_BREAK(starttagloop);
858             }
859             clearStackBackTo(eltPos);
860             pop();
861             mode = IN_TABLE_BODY;
862             continue;
863           }
864           default:;  // fall through
865         }
866         [[fallthrough]];
867       }
868       case IN_TABLE_BODY: {
869         switch (group) {
870           case TR: {
871             clearStackBackTo(
872                 findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
873             appendToCurrentNodeAndPushElement(elementName, attributes);
874             mode = IN_ROW;
875             attributes = nullptr;
876             NS_HTML5_BREAK(starttagloop);
877           }
878           case TD_OR_TH: {
879             errStartTagInTableBody(name);
880             clearStackBackTo(
881                 findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
882             appendToCurrentNodeAndPushElement(
883                 nsHtml5ElementName::ELT_TR,
884                 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
885             mode = IN_ROW;
886             continue;
887           }
888           case CAPTION:
889           case COL:
890           case COLGROUP:
891           case TBODY_OR_THEAD_OR_TFOOT: {
892             eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
893             if (!eltPos || stack[eltPos]->getGroup() == TEMPLATE) {
894               MOZ_ASSERT(fragment || isTemplateContents());
895               errStrayStartTag(name);
896               NS_HTML5_BREAK(starttagloop);
897             } else {
898               clearStackBackTo(eltPos);
899               pop();
900               mode = IN_TABLE;
901               continue;
902             }
903           }
904           default:;  // fall through
905         }
906         [[fallthrough]];
907       }
908       case IN_TABLE: {
909         for (;;) {
910           switch (group) {
911             case CAPTION: {
912               clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
913               insertMarker();
914               appendToCurrentNodeAndPushElement(elementName, attributes);
915               mode = IN_CAPTION;
916               attributes = nullptr;
917               NS_HTML5_BREAK(starttagloop);
918             }
919             case COLGROUP: {
920               clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
921               appendToCurrentNodeAndPushElement(elementName, attributes);
922               mode = IN_COLUMN_GROUP;
923               attributes = nullptr;
924               NS_HTML5_BREAK(starttagloop);
925             }
926             case COL: {
927               clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
928               appendToCurrentNodeAndPushElement(
929                   nsHtml5ElementName::ELT_COLGROUP,
930                   nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
931               mode = IN_COLUMN_GROUP;
932               NS_HTML5_CONTINUE(starttagloop);
933             }
934             case TBODY_OR_THEAD_OR_TFOOT: {
935               clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
936               appendToCurrentNodeAndPushElement(elementName, attributes);
937               mode = IN_TABLE_BODY;
938               attributes = nullptr;
939               NS_HTML5_BREAK(starttagloop);
940             }
941             case TR:
942             case TD_OR_TH: {
943               clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
944               appendToCurrentNodeAndPushElement(
945                   nsHtml5ElementName::ELT_TBODY,
946                   nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
947               mode = IN_TABLE_BODY;
948               NS_HTML5_CONTINUE(starttagloop);
949             }
950             case TEMPLATE: {
951               NS_HTML5_BREAK(intableloop);
952             }
953             case TABLE: {
954               errTableSeenWhileTableOpen();
955               eltPos = findLastInTableScope(name);
956               if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
957                 MOZ_ASSERT(fragment || isTemplateContents());
958                 NS_HTML5_BREAK(starttagloop);
959               }
960               generateImpliedEndTags();
961               if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(nsGkAtoms::table)) {
962                 errNoCheckUnclosedElementsOnStack();
963               }
964               while (currentPtr >= eltPos) {
965                 pop();
966               }
967               resetTheInsertionMode();
968               NS_HTML5_CONTINUE(starttagloop);
969             }
970             case SCRIPT: {
971               appendToCurrentNodeAndPushElement(elementName, attributes);
972               originalMode = mode;
973               mode = TEXT;
974               tokenizer->setStateAndEndTagExpectation(
975                   nsHtml5Tokenizer::SCRIPT_DATA, elementName);
976               attributes = nullptr;
977               NS_HTML5_BREAK(starttagloop);
978             }
979             case STYLE: {
980               appendToCurrentNodeAndPushElement(elementName, attributes);
981               originalMode = mode;
982               mode = TEXT;
983               tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
984                                                       elementName);
985               attributes = nullptr;
986               NS_HTML5_BREAK(starttagloop);
987             }
988             case INPUT: {
989               errStartTagInTable(name);
990               if (!nsHtml5Portability::
991                       lowerCaseLiteralEqualsIgnoreAsciiCaseString(
992                           "hidden", attributes->getValue(
993                                         nsHtml5AttributeName::ATTR_TYPE))) {
994                 NS_HTML5_BREAK(intableloop);
995               }
996               appendVoidInputToCurrent(attributes, formPointer);
997               selfClosing = false;
998               attributes = nullptr;
999               NS_HTML5_BREAK(starttagloop);
1000             }
1001             case FORM: {
1002               if (!!formPointer || isTemplateContents()) {
1003                 errFormWhenFormOpen();
1004                 NS_HTML5_BREAK(starttagloop);
1005               } else {
1006                 errStartTagInTable(name);
1007                 appendVoidFormToCurrent(attributes);
1008                 attributes = nullptr;
1009                 NS_HTML5_BREAK(starttagloop);
1010               }
1011             }
1012             default: {
1013               errStartTagInTable(name);
1014               NS_HTML5_BREAK(intableloop);
1015             }
1016           }
1017         }
1018       intableloop_end:;
1019         [[fallthrough]];
1020       }
1021       case IN_CAPTION: {
1022         switch (group) {
1023           case CAPTION:
1024           case COL:
1025           case COLGROUP:
1026           case TBODY_OR_THEAD_OR_TFOOT:
1027           case TR:
1028           case TD_OR_TH: {
1029             eltPos = findLastInTableScope(nsGkAtoms::caption);
1030             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1031               MOZ_ASSERT(fragment || isTemplateContents());
1032               errStrayStartTag(name);
1033               NS_HTML5_BREAK(starttagloop);
1034             }
1035             generateImpliedEndTags();
1036             if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
1037               errNoCheckUnclosedElementsOnStack();
1038             }
1039             while (currentPtr >= eltPos) {
1040               pop();
1041             }
1042             clearTheListOfActiveFormattingElementsUpToTheLastMarker();
1043             mode = IN_TABLE;
1044             continue;
1045           }
1046           default:;  // fall through
1047         }
1048         [[fallthrough]];
1049       }
1050       case IN_CELL: {
1051         switch (group) {
1052           case CAPTION:
1053           case COL:
1054           case COLGROUP:
1055           case TBODY_OR_THEAD_OR_TFOOT:
1056           case TR:
1057           case TD_OR_TH: {
1058             eltPos = findLastInTableScopeTdTh();
1059             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1060               errNoCellToClose();
1061               NS_HTML5_BREAK(starttagloop);
1062             } else {
1063               closeTheCell(eltPos);
1064               continue;
1065             }
1066           }
1067           default:;  // fall through
1068         }
1069         [[fallthrough]];
1070       }
1071       case FRAMESET_OK: {
1072         switch (group) {
1073           case FRAMESET: {
1074             if (mode == FRAMESET_OK) {
1075               if (!currentPtr || stack[1]->getGroup() != BODY) {
1076                 MOZ_ASSERT(fragment || isTemplateContents());
1077                 errStrayStartTag(name);
1078                 NS_HTML5_BREAK(starttagloop);
1079               } else {
1080                 errFramesetStart();
1081                 detachFromParent(stack[1]->node);
1082                 while (currentPtr > 0) {
1083                   pop();
1084                 }
1085                 appendToCurrentNodeAndPushElement(elementName, attributes);
1086                 mode = IN_FRAMESET;
1087                 attributes = nullptr;
1088                 NS_HTML5_BREAK(starttagloop);
1089               }
1090             } else {
1091               errStrayStartTag(name);
1092               NS_HTML5_BREAK(starttagloop);
1093             }
1094           }
1095           case PRE_OR_LISTING:
1096           case LI:
1097           case DD_OR_DT:
1098           case BUTTON:
1099           case MARQUEE_OR_APPLET:
1100           case OBJECT:
1101           case TABLE:
1102           case AREA_OR_WBR:
1103           case KEYGEN:
1104           case BR:
1105           case EMBED:
1106           case IMG:
1107           case INPUT:
1108           case HR:
1109           case TEXTAREA:
1110           case XMP:
1111           case IFRAME:
1112           case SELECT: {
1113             if (mode == FRAMESET_OK &&
1114                 !(group == INPUT &&
1115                   nsHtml5Portability::
1116                       lowerCaseLiteralEqualsIgnoreAsciiCaseString(
1117                           "hidden", attributes->getValue(
1118                                         nsHtml5AttributeName::ATTR_TYPE)))) {
1119               framesetOk = false;
1120               mode = IN_BODY;
1121             }
1122             [[fallthrough]];
1123           }
1124           default:;  // fall through
1125         }
1126         [[fallthrough]];
1127       }
1128       case IN_BODY: {
1129         for (;;) {
1130           switch (group) {
1131             case HTML: {
1132               errStrayStartTag(name);
1133               if (!fragment && !isTemplateContents()) {
1134                 addAttributesToHtml(attributes);
1135                 attributes = nullptr;
1136               }
1137               NS_HTML5_BREAK(starttagloop);
1138             }
1139             case BASE:
1140             case LINK_OR_BASEFONT_OR_BGSOUND:
1141             case META:
1142             case STYLE:
1143             case SCRIPT:
1144             case TITLE:
1145             case TEMPLATE: {
1146               NS_HTML5_BREAK(inbodyloop);
1147             }
1148             case BODY: {
1149               if (!currentPtr || stack[1]->getGroup() != BODY ||
1150                   isTemplateContents()) {
1151                 MOZ_ASSERT(fragment || isTemplateContents());
1152                 errStrayStartTag(name);
1153                 NS_HTML5_BREAK(starttagloop);
1154               }
1155               errFooSeenWhenFooOpen(name);
1156               framesetOk = false;
1157               if (mode == FRAMESET_OK) {
1158                 mode = IN_BODY;
1159               }
1160               if (addAttributesToBody(attributes)) {
1161                 attributes = nullptr;
1162               }
1163               NS_HTML5_BREAK(starttagloop);
1164             }
1165             case P:
1166             case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
1167             case UL_OR_OL_OR_DL:
1168             case ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY: {
1169               implicitlyCloseP();
1170               appendToCurrentNodeAndPushElementMayFoster(elementName,
1171                                                          attributes);
1172               attributes = nullptr;
1173               NS_HTML5_BREAK(starttagloop);
1174             }
1175             case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: {
1176               implicitlyCloseP();
1177               if (stack[currentPtr]->getGroup() ==
1178                   H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
1179                 errHeadingWhenHeadingOpen();
1180                 pop();
1181               }
1182               appendToCurrentNodeAndPushElementMayFoster(elementName,
1183                                                          attributes);
1184               attributes = nullptr;
1185               NS_HTML5_BREAK(starttagloop);
1186             }
1187             case FIELDSET: {
1188               implicitlyCloseP();
1189               appendToCurrentNodeAndPushElementMayFoster(
1190                   elementName, attributes, formPointer);
1191               attributes = nullptr;
1192               NS_HTML5_BREAK(starttagloop);
1193             }
1194             case PRE_OR_LISTING: {
1195               implicitlyCloseP();
1196               appendToCurrentNodeAndPushElementMayFoster(elementName,
1197                                                          attributes);
1198               needToDropLF = true;
1199               attributes = nullptr;
1200               NS_HTML5_BREAK(starttagloop);
1201             }
1202             case FORM: {
1203               if (!!formPointer && !isTemplateContents()) {
1204                 errFormWhenFormOpen();
1205                 NS_HTML5_BREAK(starttagloop);
1206               } else {
1207                 implicitlyCloseP();
1208                 appendToCurrentNodeAndPushFormElementMayFoster(attributes);
1209                 attributes = nullptr;
1210                 NS_HTML5_BREAK(starttagloop);
1211               }
1212             }
1213             case LI:
1214             case DD_OR_DT: {
1215               eltPos = currentPtr;
1216               for (;;) {
1217                 nsHtml5StackNode* node = stack[eltPos];
1218                 if (node->getGroup() == group) {
1219                   generateImpliedEndTagsExceptFor(node->name);
1220                   if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
1221                     errUnclosedElementsImplied(eltPos, name);
1222                   }
1223                   while (currentPtr >= eltPos) {
1224                     pop();
1225                   }
1226                   break;
1227                 } else if (!eltPos || (node->isSpecial() &&
1228                                        (node->ns != kNameSpaceID_XHTML ||
1229                                         (node->name != nsGkAtoms::p &&
1230                                          node->name != nsGkAtoms::address &&
1231                                          node->name != nsGkAtoms::div)))) {
1232                   break;
1233                 }
1234                 eltPos--;
1235               }
1236               implicitlyCloseP();
1237               appendToCurrentNodeAndPushElementMayFoster(elementName,
1238                                                          attributes);
1239               attributes = nullptr;
1240               NS_HTML5_BREAK(starttagloop);
1241             }
1242             case PLAINTEXT: {
1243               implicitlyCloseP();
1244               appendToCurrentNodeAndPushElementMayFoster(elementName,
1245                                                          attributes);
1246               tokenizer->setStateAndEndTagExpectation(
1247                   nsHtml5Tokenizer::PLAINTEXT, elementName);
1248               attributes = nullptr;
1249               NS_HTML5_BREAK(starttagloop);
1250             }
1251             case A: {
1252               int32_t activeAPos =
1253                   findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(
1254                       nsGkAtoms::a);
1255               if (activeAPos != -1) {
1256                 errFooSeenWhenFooOpen(name);
1257                 nsHtml5StackNode* activeA =
1258                     listOfActiveFormattingElements[activeAPos];
1259                 activeA->retain();
1260                 adoptionAgencyEndTag(nsGkAtoms::a);
1261                 removeFromStack(activeA);
1262                 activeAPos = findInListOfActiveFormattingElements(activeA);
1263                 if (activeAPos != -1) {
1264                   removeFromListOfActiveFormattingElements(activeAPos);
1265                 }
1266                 activeA->release(this);
1267               }
1268               reconstructTheActiveFormattingElements();
1269               appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
1270                                                                    attributes);
1271               attributes = nullptr;
1272               NS_HTML5_BREAK(starttagloop);
1273             }
1274             case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
1275             case FONT: {
1276               reconstructTheActiveFormattingElements();
1277               maybeForgetEarlierDuplicateFormattingElement(
1278                   elementName->getName(), attributes);
1279               appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
1280                                                                    attributes);
1281               attributes = nullptr;
1282               NS_HTML5_BREAK(starttagloop);
1283             }
1284             case NOBR: {
1285               reconstructTheActiveFormattingElements();
1286               if (nsHtml5TreeBuilder::NOT_FOUND_ON_STACK !=
1287                   findLastInScope(nsGkAtoms::nobr)) {
1288                 errFooSeenWhenFooOpen(name);
1289                 adoptionAgencyEndTag(nsGkAtoms::nobr);
1290                 reconstructTheActiveFormattingElements();
1291               }
1292               appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
1293                                                                    attributes);
1294               attributes = nullptr;
1295               NS_HTML5_BREAK(starttagloop);
1296             }
1297             case BUTTON: {
1298               eltPos = findLastInScope(name);
1299               if (eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1300                 errFooSeenWhenFooOpen(name);
1301                 generateImpliedEndTags();
1302                 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
1303                   errUnclosedElementsImplied(eltPos, name);
1304                 }
1305                 while (currentPtr >= eltPos) {
1306                   pop();
1307                 }
1308                 NS_HTML5_CONTINUE(starttagloop);
1309               } else {
1310                 reconstructTheActiveFormattingElements();
1311                 appendToCurrentNodeAndPushElementMayFoster(
1312                     elementName, attributes, formPointer);
1313                 attributes = nullptr;
1314                 NS_HTML5_BREAK(starttagloop);
1315               }
1316             }
1317             case OBJECT: {
1318               reconstructTheActiveFormattingElements();
1319               appendToCurrentNodeAndPushElementMayFoster(
1320                   elementName, attributes, formPointer);
1321               insertMarker();
1322               attributes = nullptr;
1323               NS_HTML5_BREAK(starttagloop);
1324             }
1325             case MARQUEE_OR_APPLET: {
1326               reconstructTheActiveFormattingElements();
1327               appendToCurrentNodeAndPushElementMayFoster(elementName,
1328                                                          attributes);
1329               insertMarker();
1330               attributes = nullptr;
1331               NS_HTML5_BREAK(starttagloop);
1332             }
1333             case TABLE: {
1334               if (!quirks) {
1335                 implicitlyCloseP();
1336               }
1337               appendToCurrentNodeAndPushElementMayFoster(elementName,
1338                                                          attributes);
1339               mode = IN_TABLE;
1340               attributes = nullptr;
1341               NS_HTML5_BREAK(starttagloop);
1342             }
1343             case BR:
1344             case EMBED:
1345             case AREA_OR_WBR:
1346             case KEYGEN: {
1347               reconstructTheActiveFormattingElements();
1348               [[fallthrough]];
1349             }
1350 #ifdef ENABLE_VOID_MENUITEM
1351             case MENUITEM:
1352 #endif
1353             case PARAM_OR_SOURCE_OR_TRACK: {
1354               appendVoidElementToCurrentMayFoster(elementName, attributes);
1355               selfClosing = false;
1356               attributes = nullptr;
1357               NS_HTML5_BREAK(starttagloop);
1358             }
1359             case HR: {
1360               implicitlyCloseP();
1361               appendVoidElementToCurrentMayFoster(elementName, attributes);
1362               selfClosing = false;
1363               attributes = nullptr;
1364               NS_HTML5_BREAK(starttagloop);
1365             }
1366             case IMAGE: {
1367               errImage();
1368               elementName = nsHtml5ElementName::ELT_IMG;
1369               NS_HTML5_CONTINUE(starttagloop);
1370             }
1371             case IMG:
1372             case INPUT: {
1373               reconstructTheActiveFormattingElements();
1374               appendVoidElementToCurrentMayFoster(elementName, attributes,
1375                                                   formPointer);
1376               selfClosing = false;
1377               attributes = nullptr;
1378               NS_HTML5_BREAK(starttagloop);
1379             }
1380             case TEXTAREA: {
1381               appendToCurrentNodeAndPushElementMayFoster(
1382                   elementName, attributes, formPointer);
1383               tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
1384                                                       elementName);
1385               originalMode = mode;
1386               mode = TEXT;
1387               needToDropLF = true;
1388               attributes = nullptr;
1389               NS_HTML5_BREAK(starttagloop);
1390             }
1391             case XMP: {
1392               implicitlyCloseP();
1393               reconstructTheActiveFormattingElements();
1394               appendToCurrentNodeAndPushElementMayFoster(elementName,
1395                                                          attributes);
1396               originalMode = mode;
1397               mode = TEXT;
1398               tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1399                                                       elementName);
1400               attributes = nullptr;
1401               NS_HTML5_BREAK(starttagloop);
1402             }
1403             case NOSCRIPT: {
1404               if (!scriptingEnabled) {
1405                 reconstructTheActiveFormattingElements();
1406                 appendToCurrentNodeAndPushElementMayFoster(elementName,
1407                                                            attributes);
1408                 attributes = nullptr;
1409                 NS_HTML5_BREAK(starttagloop);
1410               }
1411               [[fallthrough]];
1412             }
1413             case NOFRAMES:
1414             case IFRAME:
1415             case NOEMBED: {
1416               startTagGenericRawText(elementName, attributes);
1417               attributes = nullptr;
1418               NS_HTML5_BREAK(starttagloop);
1419             }
1420             case SELECT: {
1421               reconstructTheActiveFormattingElements();
1422               appendToCurrentNodeAndPushElementMayFoster(
1423                   elementName, attributes, formPointer);
1424               switch (mode) {
1425                 case IN_TABLE:
1426                 case IN_CAPTION:
1427                 case IN_COLUMN_GROUP:
1428                 case IN_TABLE_BODY:
1429                 case IN_ROW:
1430                 case IN_CELL: {
1431                   mode = IN_SELECT_IN_TABLE;
1432                   break;
1433                 }
1434                 default: {
1435                   mode = IN_SELECT;
1436                   break;
1437                 }
1438               }
1439               attributes = nullptr;
1440               NS_HTML5_BREAK(starttagloop);
1441             }
1442             case OPTGROUP:
1443             case OPTION: {
1444               if (isCurrent(nsGkAtoms::option)) {
1445                 pop();
1446               }
1447               reconstructTheActiveFormattingElements();
1448               appendToCurrentNodeAndPushElementMayFoster(elementName,
1449                                                          attributes);
1450               attributes = nullptr;
1451               NS_HTML5_BREAK(starttagloop);
1452             }
1453             case RB_OR_RTC: {
1454               eltPos = findLastInScope(nsGkAtoms::ruby);
1455               if (eltPos != NOT_FOUND_ON_STACK) {
1456                 generateImpliedEndTags();
1457               }
1458               if (eltPos != currentPtr) {
1459                 if (eltPos == NOT_FOUND_ON_STACK) {
1460                   errStartTagSeenWithoutRuby(name);
1461                 } else {
1462                   errUnclosedChildrenInRuby();
1463                 }
1464               }
1465               appendToCurrentNodeAndPushElementMayFoster(elementName,
1466                                                          attributes);
1467               attributes = nullptr;
1468               NS_HTML5_BREAK(starttagloop);
1469             }
1470             case RT_OR_RP: {
1471               eltPos = findLastInScope(nsGkAtoms::ruby);
1472               if (eltPos != NOT_FOUND_ON_STACK) {
1473                 generateImpliedEndTagsExceptFor(nsGkAtoms::rtc);
1474               }
1475               if (eltPos != currentPtr) {
1476                 if (!isCurrent(nsGkAtoms::rtc)) {
1477                   if (eltPos == NOT_FOUND_ON_STACK) {
1478                     errStartTagSeenWithoutRuby(name);
1479                   } else {
1480                     errUnclosedChildrenInRuby();
1481                   }
1482                 }
1483               }
1484               appendToCurrentNodeAndPushElementMayFoster(elementName,
1485                                                          attributes);
1486               attributes = nullptr;
1487               NS_HTML5_BREAK(starttagloop);
1488             }
1489             case MATH: {
1490               reconstructTheActiveFormattingElements();
1491               attributes->adjustForMath();
1492               if (selfClosing) {
1493                 appendVoidElementToCurrentMayFosterMathML(elementName,
1494                                                           attributes);
1495                 selfClosing = false;
1496               } else {
1497                 appendToCurrentNodeAndPushElementMayFosterMathML(elementName,
1498                                                                  attributes);
1499               }
1500               attributes = nullptr;
1501               NS_HTML5_BREAK(starttagloop);
1502             }
1503             case SVG: {
1504               reconstructTheActiveFormattingElements();
1505               attributes->adjustForSvg();
1506               if (selfClosing) {
1507                 appendVoidElementToCurrentMayFosterSVG(elementName, attributes);
1508                 selfClosing = false;
1509               } else {
1510                 appendToCurrentNodeAndPushElementMayFosterSVG(elementName,
1511                                                               attributes);
1512               }
1513               attributes = nullptr;
1514               NS_HTML5_BREAK(starttagloop);
1515             }
1516             case CAPTION:
1517             case COL:
1518             case COLGROUP:
1519             case TBODY_OR_THEAD_OR_TFOOT:
1520             case TR:
1521             case TD_OR_TH:
1522             case FRAME:
1523             case FRAMESET:
1524             case HEAD: {
1525               errStrayStartTag(name);
1526               NS_HTML5_BREAK(starttagloop);
1527             }
1528             case OUTPUT: {
1529               reconstructTheActiveFormattingElements();
1530               appendToCurrentNodeAndPushElementMayFoster(
1531                   elementName, attributes, formPointer);
1532               attributes = nullptr;
1533               NS_HTML5_BREAK(starttagloop);
1534             }
1535             default: {
1536               reconstructTheActiveFormattingElements();
1537               appendToCurrentNodeAndPushElementMayFoster(elementName,
1538                                                          attributes);
1539               attributes = nullptr;
1540               NS_HTML5_BREAK(starttagloop);
1541             }
1542           }
1543         }
1544       inbodyloop_end:;
1545         [[fallthrough]];
1546       }
1547       case IN_HEAD: {
1548         for (;;) {
1549           switch (group) {
1550             case HTML: {
1551               errStrayStartTag(name);
1552               if (!fragment && !isTemplateContents()) {
1553                 addAttributesToHtml(attributes);
1554                 attributes = nullptr;
1555               }
1556               NS_HTML5_BREAK(starttagloop);
1557             }
1558             case BASE:
1559             case LINK_OR_BASEFONT_OR_BGSOUND: {
1560               appendVoidElementToCurrentMayFoster(elementName, attributes);
1561               selfClosing = false;
1562               attributes = nullptr;
1563               NS_HTML5_BREAK(starttagloop);
1564             }
1565             case META: {
1566               NS_HTML5_BREAK(inheadloop);
1567             }
1568             case TITLE: {
1569               startTagTitleInHead(elementName, attributes);
1570               attributes = nullptr;
1571               NS_HTML5_BREAK(starttagloop);
1572             }
1573             case NOSCRIPT: {
1574               if (scriptingEnabled) {
1575                 appendToCurrentNodeAndPushElement(elementName, attributes);
1576                 originalMode = mode;
1577                 mode = TEXT;
1578                 tokenizer->setStateAndEndTagExpectation(
1579                     nsHtml5Tokenizer::RAWTEXT, elementName);
1580               } else {
1581                 appendToCurrentNodeAndPushElementMayFoster(elementName,
1582                                                            attributes);
1583                 mode = IN_HEAD_NOSCRIPT;
1584               }
1585               attributes = nullptr;
1586               NS_HTML5_BREAK(starttagloop);
1587             }
1588             case SCRIPT: {
1589               startTagScriptInHead(elementName, attributes);
1590               attributes = nullptr;
1591               NS_HTML5_BREAK(starttagloop);
1592             }
1593             case STYLE:
1594             case NOFRAMES: {
1595               startTagGenericRawText(elementName, attributes);
1596               attributes = nullptr;
1597               NS_HTML5_BREAK(starttagloop);
1598             }
1599             case HEAD: {
1600               errFooSeenWhenFooOpen(name);
1601               NS_HTML5_BREAK(starttagloop);
1602             }
1603             case TEMPLATE: {
1604               startTagTemplateInHead(elementName, attributes);
1605               attributes = nullptr;
1606               NS_HTML5_BREAK(starttagloop);
1607             }
1608             default: {
1609               pop();
1610               mode = AFTER_HEAD;
1611               NS_HTML5_CONTINUE(starttagloop);
1612             }
1613           }
1614         }
1615       inheadloop_end:;
1616         [[fallthrough]];
1617       }
1618       case IN_HEAD_NOSCRIPT: {
1619         switch (group) {
1620           case HTML: {
1621             errStrayStartTag(name);
1622             if (!fragment && !isTemplateContents()) {
1623               addAttributesToHtml(attributes);
1624               attributes = nullptr;
1625             }
1626             NS_HTML5_BREAK(starttagloop);
1627           }
1628           case LINK_OR_BASEFONT_OR_BGSOUND: {
1629             appendVoidElementToCurrentMayFoster(elementName, attributes);
1630             selfClosing = false;
1631             attributes = nullptr;
1632             NS_HTML5_BREAK(starttagloop);
1633           }
1634           case META: {
1635             checkMetaCharset(attributes);
1636             appendVoidElementToCurrentMayFoster(elementName, attributes);
1637             selfClosing = false;
1638             attributes = nullptr;
1639             NS_HTML5_BREAK(starttagloop);
1640           }
1641           case STYLE:
1642           case NOFRAMES: {
1643             appendToCurrentNodeAndPushElement(elementName, attributes);
1644             originalMode = mode;
1645             mode = TEXT;
1646             tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1647                                                     elementName);
1648             attributes = nullptr;
1649             NS_HTML5_BREAK(starttagloop);
1650           }
1651           case HEAD: {
1652             errFooSeenWhenFooOpen(name);
1653             NS_HTML5_BREAK(starttagloop);
1654           }
1655           case NOSCRIPT: {
1656             errFooSeenWhenFooOpen(name);
1657             NS_HTML5_BREAK(starttagloop);
1658           }
1659           default: {
1660             errBadStartTagInNoscriptInHead(name);
1661             pop();
1662             mode = IN_HEAD;
1663             continue;
1664           }
1665         }
1666       }
1667       case IN_COLUMN_GROUP: {
1668         switch (group) {
1669           case HTML: {
1670             errStrayStartTag(name);
1671             if (!fragment && !isTemplateContents()) {
1672               addAttributesToHtml(attributes);
1673               attributes = nullptr;
1674             }
1675             NS_HTML5_BREAK(starttagloop);
1676           }
1677           case COL: {
1678             appendVoidElementToCurrentMayFoster(elementName, attributes);
1679             selfClosing = false;
1680             attributes = nullptr;
1681             NS_HTML5_BREAK(starttagloop);
1682           }
1683           case TEMPLATE: {
1684             startTagTemplateInHead(elementName, attributes);
1685             attributes = nullptr;
1686             NS_HTML5_BREAK(starttagloop);
1687           }
1688           default: {
1689             if (!currentPtr || stack[currentPtr]->getGroup() == TEMPLATE) {
1690               MOZ_ASSERT(fragment || isTemplateContents());
1691               errGarbageInColgroup();
1692               NS_HTML5_BREAK(starttagloop);
1693             }
1694             pop();
1695             mode = IN_TABLE;
1696             continue;
1697           }
1698         }
1699       }
1700       case IN_SELECT_IN_TABLE: {
1701         switch (group) {
1702           case CAPTION:
1703           case TBODY_OR_THEAD_OR_TFOOT:
1704           case TR:
1705           case TD_OR_TH:
1706           case TABLE: {
1707             errStartTagWithSelectOpen(name);
1708             eltPos = findLastInTableScope(nsGkAtoms::select);
1709             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1710               MOZ_ASSERT(fragment);
1711               NS_HTML5_BREAK(starttagloop);
1712             }
1713             while (currentPtr >= eltPos) {
1714               pop();
1715             }
1716             resetTheInsertionMode();
1717             continue;
1718           }
1719           default:;  // fall through
1720         }
1721         [[fallthrough]];
1722       }
1723       case IN_SELECT: {
1724         switch (group) {
1725           case HTML: {
1726             errStrayStartTag(name);
1727             if (!fragment) {
1728               addAttributesToHtml(attributes);
1729               attributes = nullptr;
1730             }
1731             NS_HTML5_BREAK(starttagloop);
1732           }
1733           case OPTION: {
1734             if (isCurrent(nsGkAtoms::option)) {
1735               pop();
1736             }
1737             appendToCurrentNodeAndPushElement(elementName, attributes);
1738             attributes = nullptr;
1739             NS_HTML5_BREAK(starttagloop);
1740           }
1741           case OPTGROUP: {
1742             if (isCurrent(nsGkAtoms::option)) {
1743               pop();
1744             }
1745             if (isCurrent(nsGkAtoms::optgroup)) {
1746               pop();
1747             }
1748             appendToCurrentNodeAndPushElement(elementName, attributes);
1749             attributes = nullptr;
1750             NS_HTML5_BREAK(starttagloop);
1751           }
1752           case SELECT: {
1753             errStartSelectWhereEndSelectExpected();
1754             eltPos = findLastInTableScope(name);
1755             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1756               MOZ_ASSERT(fragment);
1757               errNoSelectInTableScope();
1758               NS_HTML5_BREAK(starttagloop);
1759             } else {
1760               while (currentPtr >= eltPos) {
1761                 pop();
1762               }
1763               resetTheInsertionMode();
1764               NS_HTML5_BREAK(starttagloop);
1765             }
1766           }
1767           case INPUT:
1768           case TEXTAREA: {
1769             errStartTagWithSelectOpen(name);
1770             eltPos = findLastInTableScope(nsGkAtoms::select);
1771             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
1772               MOZ_ASSERT(fragment);
1773               NS_HTML5_BREAK(starttagloop);
1774             }
1775             while (currentPtr >= eltPos) {
1776               pop();
1777             }
1778             resetTheInsertionMode();
1779             continue;
1780           }
1781           case SCRIPT: {
1782             startTagScriptInHead(elementName, attributes);
1783             attributes = nullptr;
1784             NS_HTML5_BREAK(starttagloop);
1785           }
1786           case TEMPLATE: {
1787             startTagTemplateInHead(elementName, attributes);
1788             attributes = nullptr;
1789             NS_HTML5_BREAK(starttagloop);
1790           }
1791           default: {
1792             errStrayStartTag(name);
1793             NS_HTML5_BREAK(starttagloop);
1794           }
1795         }
1796       }
1797       case AFTER_BODY: {
1798         switch (group) {
1799           case HTML: {
1800             errStrayStartTag(name);
1801             if (!fragment && !isTemplateContents()) {
1802               addAttributesToHtml(attributes);
1803               attributes = nullptr;
1804             }
1805             NS_HTML5_BREAK(starttagloop);
1806           }
1807           default: {
1808             errStrayStartTag(name);
1809             mode = framesetOk ? FRAMESET_OK : IN_BODY;
1810             continue;
1811           }
1812         }
1813       }
1814       case IN_FRAMESET: {
1815         switch (group) {
1816           case FRAMESET: {
1817             appendToCurrentNodeAndPushElement(elementName, attributes);
1818             attributes = nullptr;
1819             NS_HTML5_BREAK(starttagloop);
1820           }
1821           case FRAME: {
1822             appendVoidElementToCurrentMayFoster(elementName, attributes);
1823             selfClosing = false;
1824             attributes = nullptr;
1825             NS_HTML5_BREAK(starttagloop);
1826           }
1827           default:;  // fall through
1828         }
1829         [[fallthrough]];
1830       }
1831       case AFTER_FRAMESET: {
1832         switch (group) {
1833           case HTML: {
1834             errStrayStartTag(name);
1835             if (!fragment && !isTemplateContents()) {
1836               addAttributesToHtml(attributes);
1837               attributes = nullptr;
1838             }
1839             NS_HTML5_BREAK(starttagloop);
1840           }
1841           case NOFRAMES: {
1842             appendToCurrentNodeAndPushElement(elementName, attributes);
1843             originalMode = mode;
1844             mode = TEXT;
1845             tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1846                                                     elementName);
1847             attributes = nullptr;
1848             NS_HTML5_BREAK(starttagloop);
1849           }
1850           default: {
1851             errStrayStartTag(name);
1852             NS_HTML5_BREAK(starttagloop);
1853           }
1854         }
1855       }
1856       case INITIAL: {
1857         errStartTagWithoutDoctype();
1858         documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
1859         mode = BEFORE_HTML;
1860         continue;
1861       }
1862       case BEFORE_HTML: {
1863         switch (group) {
1864           case HTML: {
1865             if (attributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
1866               appendHtmlElementToDocumentAndPush();
1867             } else {
1868               appendHtmlElementToDocumentAndPush(attributes);
1869             }
1870             mode = BEFORE_HEAD;
1871             attributes = nullptr;
1872             NS_HTML5_BREAK(starttagloop);
1873           }
1874           default: {
1875             appendHtmlElementToDocumentAndPush();
1876             mode = BEFORE_HEAD;
1877             continue;
1878           }
1879         }
1880       }
1881       case BEFORE_HEAD: {
1882         switch (group) {
1883           case HTML: {
1884             errStrayStartTag(name);
1885             if (!fragment && !isTemplateContents()) {
1886               addAttributesToHtml(attributes);
1887               attributes = nullptr;
1888             }
1889             NS_HTML5_BREAK(starttagloop);
1890           }
1891           case HEAD: {
1892             appendToCurrentNodeAndPushHeadElement(attributes);
1893             mode = IN_HEAD;
1894             attributes = nullptr;
1895             NS_HTML5_BREAK(starttagloop);
1896           }
1897           default: {
1898             appendToCurrentNodeAndPushHeadElement(
1899                 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
1900             mode = IN_HEAD;
1901             continue;
1902           }
1903         }
1904       }
1905       case AFTER_HEAD: {
1906         switch (group) {
1907           case HTML: {
1908             errStrayStartTag(name);
1909             if (!fragment && !isTemplateContents()) {
1910               addAttributesToHtml(attributes);
1911               attributes = nullptr;
1912             }
1913             NS_HTML5_BREAK(starttagloop);
1914           }
1915           case BODY: {
1916             if (!attributes->getLength()) {
1917               appendToCurrentNodeAndPushBodyElement();
1918             } else {
1919               appendToCurrentNodeAndPushBodyElement(attributes);
1920             }
1921             framesetOk = false;
1922             mode = IN_BODY;
1923             attributes = nullptr;
1924             NS_HTML5_BREAK(starttagloop);
1925           }
1926           case FRAMESET: {
1927             appendToCurrentNodeAndPushElement(elementName, attributes);
1928             mode = IN_FRAMESET;
1929             attributes = nullptr;
1930             NS_HTML5_BREAK(starttagloop);
1931           }
1932           case TEMPLATE: {
1933             errFooBetweenHeadAndBody(name);
1934             pushHeadPointerOntoStack();
1935             nsHtml5StackNode* headOnStack = stack[currentPtr];
1936             startTagTemplateInHead(elementName, attributes);
1937             removeFromStack(headOnStack);
1938             attributes = nullptr;
1939             NS_HTML5_BREAK(starttagloop);
1940           }
1941           case BASE:
1942           case LINK_OR_BASEFONT_OR_BGSOUND: {
1943             errFooBetweenHeadAndBody(name);
1944             pushHeadPointerOntoStack();
1945             appendVoidElementToCurrentMayFoster(elementName, attributes);
1946             selfClosing = false;
1947             pop();
1948             attributes = nullptr;
1949             NS_HTML5_BREAK(starttagloop);
1950           }
1951           case META: {
1952             errFooBetweenHeadAndBody(name);
1953             checkMetaCharset(attributes);
1954             pushHeadPointerOntoStack();
1955             appendVoidElementToCurrentMayFoster(elementName, attributes);
1956             selfClosing = false;
1957             pop();
1958             attributes = nullptr;
1959             NS_HTML5_BREAK(starttagloop);
1960           }
1961           case SCRIPT: {
1962             errFooBetweenHeadAndBody(name);
1963             pushHeadPointerOntoStack();
1964             appendToCurrentNodeAndPushElement(elementName, attributes);
1965             originalMode = mode;
1966             mode = TEXT;
1967             tokenizer->setStateAndEndTagExpectation(
1968                 nsHtml5Tokenizer::SCRIPT_DATA, elementName);
1969             attributes = nullptr;
1970             NS_HTML5_BREAK(starttagloop);
1971           }
1972           case STYLE:
1973           case NOFRAMES: {
1974             errFooBetweenHeadAndBody(name);
1975             pushHeadPointerOntoStack();
1976             appendToCurrentNodeAndPushElement(elementName, attributes);
1977             originalMode = mode;
1978             mode = TEXT;
1979             tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
1980                                                     elementName);
1981             attributes = nullptr;
1982             NS_HTML5_BREAK(starttagloop);
1983           }
1984           case TITLE: {
1985             errFooBetweenHeadAndBody(name);
1986             pushHeadPointerOntoStack();
1987             appendToCurrentNodeAndPushElement(elementName, attributes);
1988             originalMode = mode;
1989             mode = TEXT;
1990             tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
1991                                                     elementName);
1992             attributes = nullptr;
1993             NS_HTML5_BREAK(starttagloop);
1994           }
1995           case HEAD: {
1996             errStrayStartTag(name);
1997             NS_HTML5_BREAK(starttagloop);
1998           }
1999           default: {
2000             appendToCurrentNodeAndPushBodyElement();
2001             mode = FRAMESET_OK;
2002             continue;
2003           }
2004         }
2005       }
2006       case AFTER_AFTER_BODY: {
2007         switch (group) {
2008           case HTML: {
2009             errStrayStartTag(name);
2010             if (!fragment && !isTemplateContents()) {
2011               addAttributesToHtml(attributes);
2012               attributes = nullptr;
2013             }
2014             NS_HTML5_BREAK(starttagloop);
2015           }
2016           default: {
2017             errStrayStartTag(name);
2018 
2019             mode = framesetOk ? FRAMESET_OK : IN_BODY;
2020             continue;
2021           }
2022         }
2023       }
2024       case AFTER_AFTER_FRAMESET: {
2025         switch (group) {
2026           case HTML: {
2027             errStrayStartTag(name);
2028             if (!fragment && !isTemplateContents()) {
2029               addAttributesToHtml(attributes);
2030               attributes = nullptr;
2031             }
2032             NS_HTML5_BREAK(starttagloop);
2033           }
2034           case NOFRAMES: {
2035             startTagGenericRawText(elementName, attributes);
2036             attributes = nullptr;
2037             NS_HTML5_BREAK(starttagloop);
2038           }
2039           default: {
2040             errStrayStartTag(name);
2041             NS_HTML5_BREAK(starttagloop);
2042           }
2043         }
2044       }
2045       case TEXT: {
2046         MOZ_ASSERT(false);
2047         NS_HTML5_BREAK(starttagloop);
2048       }
2049     }
2050   }
2051 starttagloop_end:;
2052   if (selfClosing) {
2053     errSelfClosing();
2054   }
2055   if (!mBuilder && attributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
2056     delete attributes;
2057   }
2058 }
2059 
startTagTitleInHead(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes)2060 void nsHtml5TreeBuilder::startTagTitleInHead(
2061     nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2062   appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
2063   originalMode = mode;
2064   mode = TEXT;
2065   tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
2066                                           elementName);
2067 }
2068 
startTagGenericRawText(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes)2069 void nsHtml5TreeBuilder::startTagGenericRawText(
2070     nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2071   appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
2072   originalMode = mode;
2073   mode = TEXT;
2074   tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
2075                                           elementName);
2076 }
2077 
startTagScriptInHead(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes)2078 void nsHtml5TreeBuilder::startTagScriptInHead(
2079     nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2080   appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
2081   originalMode = mode;
2082   mode = TEXT;
2083   tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::SCRIPT_DATA,
2084                                           elementName);
2085 }
2086 
startTagTemplateInHead(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes)2087 void nsHtml5TreeBuilder::startTagTemplateInHead(
2088     nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
2089   appendToCurrentNodeAndPushElement(elementName, attributes);
2090   insertMarker();
2091   framesetOk = false;
2092   originalMode = mode;
2093   mode = IN_TEMPLATE;
2094   pushTemplateMode(IN_TEMPLATE);
2095 }
2096 
isTemplateContents()2097 bool nsHtml5TreeBuilder::isTemplateContents() {
2098   return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK !=
2099          findLast(nsGkAtoms::_template);
2100 }
2101 
isTemplateModeStackEmpty()2102 bool nsHtml5TreeBuilder::isTemplateModeStackEmpty() {
2103   return templateModePtr == -1;
2104 }
2105 
isSpecialParentInForeign(nsHtml5StackNode * stackNode)2106 bool nsHtml5TreeBuilder::isSpecialParentInForeign(nsHtml5StackNode* stackNode) {
2107   int32_t ns = stackNode->ns;
2108   return (kNameSpaceID_XHTML == ns) || (stackNode->isHtmlIntegrationPoint()) ||
2109          ((kNameSpaceID_MathML == ns) &&
2110           (stackNode->getGroup() == MI_MO_MN_MS_MTEXT));
2111 }
2112 
extractCharsetFromContent(nsHtml5String attributeValue,nsHtml5TreeBuilder * tb)2113 nsHtml5String nsHtml5TreeBuilder::extractCharsetFromContent(
2114     nsHtml5String attributeValue, nsHtml5TreeBuilder* tb) {
2115   int32_t charsetState = CHARSET_INITIAL;
2116   int32_t start = -1;
2117   int32_t end = -1;
2118   autoJArray<char16_t, int32_t> buffer =
2119       nsHtml5Portability::newCharArrayFromString(attributeValue);
2120   for (int32_t i = 0; i < buffer.length; i++) {
2121     char16_t c = buffer[i];
2122     switch (charsetState) {
2123       case CHARSET_INITIAL: {
2124         switch (c) {
2125           case 'c':
2126           case 'C': {
2127             charsetState = CHARSET_C;
2128             continue;
2129           }
2130           default: {
2131             continue;
2132           }
2133         }
2134       }
2135       case CHARSET_C: {
2136         switch (c) {
2137           case 'h':
2138           case 'H': {
2139             charsetState = CHARSET_H;
2140             continue;
2141           }
2142           default: {
2143             charsetState = CHARSET_INITIAL;
2144             continue;
2145           }
2146         }
2147       }
2148       case CHARSET_H: {
2149         switch (c) {
2150           case 'a':
2151           case 'A': {
2152             charsetState = CHARSET_A;
2153             continue;
2154           }
2155           default: {
2156             charsetState = CHARSET_INITIAL;
2157             continue;
2158           }
2159         }
2160       }
2161       case CHARSET_A: {
2162         switch (c) {
2163           case 'r':
2164           case 'R': {
2165             charsetState = CHARSET_R;
2166             continue;
2167           }
2168           default: {
2169             charsetState = CHARSET_INITIAL;
2170             continue;
2171           }
2172         }
2173       }
2174       case CHARSET_R: {
2175         switch (c) {
2176           case 's':
2177           case 'S': {
2178             charsetState = CHARSET_S;
2179             continue;
2180           }
2181           default: {
2182             charsetState = CHARSET_INITIAL;
2183             continue;
2184           }
2185         }
2186       }
2187       case CHARSET_S: {
2188         switch (c) {
2189           case 'e':
2190           case 'E': {
2191             charsetState = CHARSET_E;
2192             continue;
2193           }
2194           default: {
2195             charsetState = CHARSET_INITIAL;
2196             continue;
2197           }
2198         }
2199       }
2200       case CHARSET_E: {
2201         switch (c) {
2202           case 't':
2203           case 'T': {
2204             charsetState = CHARSET_T;
2205             continue;
2206           }
2207           default: {
2208             charsetState = CHARSET_INITIAL;
2209             continue;
2210           }
2211         }
2212       }
2213       case CHARSET_T: {
2214         switch (c) {
2215           case '\t':
2216           case '\n':
2217           case '\f':
2218           case '\r':
2219           case ' ': {
2220             continue;
2221           }
2222           case '=': {
2223             charsetState = CHARSET_EQUALS;
2224             continue;
2225           }
2226           default: {
2227             return nullptr;
2228           }
2229         }
2230       }
2231       case CHARSET_EQUALS: {
2232         switch (c) {
2233           case '\t':
2234           case '\n':
2235           case '\f':
2236           case '\r':
2237           case ' ': {
2238             continue;
2239           }
2240           case '\'': {
2241             start = i + 1;
2242             charsetState = CHARSET_SINGLE_QUOTED;
2243             continue;
2244           }
2245           case '\"': {
2246             start = i + 1;
2247             charsetState = CHARSET_DOUBLE_QUOTED;
2248             continue;
2249           }
2250           default: {
2251             start = i;
2252             charsetState = CHARSET_UNQUOTED;
2253             continue;
2254           }
2255         }
2256       }
2257       case CHARSET_SINGLE_QUOTED: {
2258         switch (c) {
2259           case '\'': {
2260             end = i;
2261             NS_HTML5_BREAK(charsetloop);
2262           }
2263           default: {
2264             continue;
2265           }
2266         }
2267       }
2268       case CHARSET_DOUBLE_QUOTED: {
2269         switch (c) {
2270           case '\"': {
2271             end = i;
2272             NS_HTML5_BREAK(charsetloop);
2273           }
2274           default: {
2275             continue;
2276           }
2277         }
2278       }
2279       case CHARSET_UNQUOTED: {
2280         switch (c) {
2281           case '\t':
2282           case '\n':
2283           case '\f':
2284           case '\r':
2285           case ' ':
2286           case ';': {
2287             end = i;
2288             NS_HTML5_BREAK(charsetloop);
2289           }
2290           default: {
2291             continue;
2292           }
2293         }
2294       }
2295     }
2296   }
2297 charsetloop_end:;
2298   if (start != -1) {
2299     if (end == -1) {
2300       if (charsetState == CHARSET_UNQUOTED) {
2301         end = buffer.length;
2302       } else {
2303         return nullptr;
2304       }
2305     }
2306     return nsHtml5Portability::newStringFromBuffer(buffer, start, end - start,
2307                                                    tb, false);
2308   }
2309   return nullptr;
2310 }
2311 
checkMetaCharset(nsHtml5HtmlAttributes * attributes)2312 void nsHtml5TreeBuilder::checkMetaCharset(nsHtml5HtmlAttributes* attributes) {
2313   nsHtml5String charset =
2314       attributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
2315   if (charset) {
2316     if (tokenizer->internalEncodingDeclaration(charset)) {
2317       requestSuspension();
2318       return;
2319     }
2320     return;
2321   }
2322   if (!nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
2323           "content-type",
2324           attributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) {
2325     return;
2326   }
2327   nsHtml5String content =
2328       attributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
2329   if (content) {
2330     nsHtml5String extract =
2331         nsHtml5TreeBuilder::extractCharsetFromContent(content, this);
2332     if (extract) {
2333       if (tokenizer->internalEncodingDeclaration(extract)) {
2334         requestSuspension();
2335       }
2336     }
2337     extract.Release();
2338   }
2339 }
2340 
endTag(nsHtml5ElementName * elementName)2341 void nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) {
2342   flushCharacters();
2343   needToDropLF = false;
2344   int32_t eltPos;
2345   int32_t group = elementName->getGroup();
2346   nsAtom* name = elementName->getName();
2347   for (;;) {
2348     if (isInForeign()) {
2349       if (stack[currentPtr]->name != name) {
2350         if (!currentPtr) {
2351           errStrayEndTag(name);
2352         } else {
2353           errEndTagDidNotMatchCurrentOpenElement(name,
2354                                                  stack[currentPtr]->popName);
2355         }
2356       }
2357       eltPos = currentPtr;
2358       int32_t origPos = currentPtr;
2359       for (;;) {
2360         if (!eltPos) {
2361           MOZ_ASSERT(fragment,
2362                      "We can get this close to the root of the stack in "
2363                      "foreign content only in the fragment case.");
2364           NS_HTML5_BREAK(endtagloop);
2365         }
2366         if (stack[eltPos]->name == name) {
2367           while (currentPtr >= eltPos) {
2368             popForeign(origPos, eltPos);
2369           }
2370           NS_HTML5_BREAK(endtagloop);
2371         }
2372         if (stack[--eltPos]->ns == kNameSpaceID_XHTML) {
2373           break;
2374         }
2375       }
2376     }
2377     switch (mode) {
2378       case IN_TEMPLATE: {
2379         switch (group) {
2380           case TEMPLATE: {
2381             break;
2382           }
2383           default: {
2384             errStrayEndTag(name);
2385             NS_HTML5_BREAK(endtagloop);
2386           }
2387         }
2388         [[fallthrough]];
2389       }
2390       case IN_ROW: {
2391         switch (group) {
2392           case TR: {
2393             eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
2394             if (!eltPos) {
2395               MOZ_ASSERT(fragment || isTemplateContents());
2396               errNoTableRowToClose();
2397               NS_HTML5_BREAK(endtagloop);
2398             }
2399             clearStackBackTo(eltPos);
2400             pop();
2401             mode = IN_TABLE_BODY;
2402             NS_HTML5_BREAK(endtagloop);
2403           }
2404           case TABLE: {
2405             eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
2406             if (!eltPos) {
2407               MOZ_ASSERT(fragment || isTemplateContents());
2408               errNoTableRowToClose();
2409               NS_HTML5_BREAK(endtagloop);
2410             }
2411             clearStackBackTo(eltPos);
2412             pop();
2413             mode = IN_TABLE_BODY;
2414             continue;
2415           }
2416           case TBODY_OR_THEAD_OR_TFOOT: {
2417             if (findLastInTableScope(name) ==
2418                 nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2419               errStrayEndTag(name);
2420               NS_HTML5_BREAK(endtagloop);
2421             }
2422             eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
2423             if (!eltPos) {
2424               MOZ_ASSERT(fragment || isTemplateContents());
2425               errNoTableRowToClose();
2426               NS_HTML5_BREAK(endtagloop);
2427             }
2428             clearStackBackTo(eltPos);
2429             pop();
2430             mode = IN_TABLE_BODY;
2431             continue;
2432           }
2433           case BODY:
2434           case CAPTION:
2435           case COL:
2436           case COLGROUP:
2437           case HTML:
2438           case TD_OR_TH: {
2439             errStrayEndTag(name);
2440             NS_HTML5_BREAK(endtagloop);
2441           }
2442           default:;  // fall through
2443         }
2444         [[fallthrough]];
2445       }
2446       case IN_TABLE_BODY: {
2447         switch (group) {
2448           case TBODY_OR_THEAD_OR_TFOOT: {
2449             eltPos = findLastOrRoot(name);
2450             if (!eltPos) {
2451               errStrayEndTag(name);
2452               NS_HTML5_BREAK(endtagloop);
2453             }
2454             clearStackBackTo(eltPos);
2455             pop();
2456             mode = IN_TABLE;
2457             NS_HTML5_BREAK(endtagloop);
2458           }
2459           case TABLE: {
2460             eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
2461             if (!eltPos || stack[eltPos]->getGroup() == TEMPLATE) {
2462               MOZ_ASSERT(fragment || isTemplateContents());
2463               errStrayEndTag(name);
2464               NS_HTML5_BREAK(endtagloop);
2465             }
2466             clearStackBackTo(eltPos);
2467             pop();
2468             mode = IN_TABLE;
2469             continue;
2470           }
2471           case BODY:
2472           case CAPTION:
2473           case COL:
2474           case COLGROUP:
2475           case HTML:
2476           case TD_OR_TH:
2477           case TR: {
2478             errStrayEndTag(name);
2479             NS_HTML5_BREAK(endtagloop);
2480           }
2481           default:;  // fall through
2482         }
2483         [[fallthrough]];
2484       }
2485       case IN_TABLE: {
2486         switch (group) {
2487           case TABLE: {
2488             eltPos = findLast(nsGkAtoms::table);
2489             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2490               MOZ_ASSERT(fragment || isTemplateContents());
2491               errStrayEndTag(name);
2492               NS_HTML5_BREAK(endtagloop);
2493             }
2494             while (currentPtr >= eltPos) {
2495               pop();
2496             }
2497             resetTheInsertionMode();
2498             NS_HTML5_BREAK(endtagloop);
2499           }
2500           case BODY:
2501           case CAPTION:
2502           case COL:
2503           case COLGROUP:
2504           case HTML:
2505           case TBODY_OR_THEAD_OR_TFOOT:
2506           case TD_OR_TH:
2507           case TR: {
2508             errStrayEndTag(name);
2509             NS_HTML5_BREAK(endtagloop);
2510           }
2511           case TEMPLATE: {
2512             break;
2513           }
2514           default: {
2515             errStrayEndTag(name);
2516           }
2517         }
2518         [[fallthrough]];
2519       }
2520       case IN_CAPTION: {
2521         switch (group) {
2522           case CAPTION: {
2523             eltPos = findLastInTableScope(nsGkAtoms::caption);
2524             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2525               NS_HTML5_BREAK(endtagloop);
2526             }
2527             generateImpliedEndTags();
2528             if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
2529               errUnclosedElements(eltPos, name);
2530             }
2531             while (currentPtr >= eltPos) {
2532               pop();
2533             }
2534             clearTheListOfActiveFormattingElementsUpToTheLastMarker();
2535             mode = IN_TABLE;
2536             NS_HTML5_BREAK(endtagloop);
2537           }
2538           case TABLE: {
2539             eltPos = findLastInTableScope(nsGkAtoms::caption);
2540             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2541               MOZ_ASSERT(fragment || isTemplateContents());
2542               errStrayEndTag(name);
2543               NS_HTML5_BREAK(endtagloop);
2544             }
2545             generateImpliedEndTags();
2546             if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
2547               errUnclosedElements(eltPos, name);
2548             }
2549             while (currentPtr >= eltPos) {
2550               pop();
2551             }
2552             clearTheListOfActiveFormattingElementsUpToTheLastMarker();
2553             mode = IN_TABLE;
2554             continue;
2555           }
2556           case BODY:
2557           case COL:
2558           case COLGROUP:
2559           case HTML:
2560           case TBODY_OR_THEAD_OR_TFOOT:
2561           case TD_OR_TH:
2562           case TR: {
2563             errStrayEndTag(name);
2564             NS_HTML5_BREAK(endtagloop);
2565           }
2566           default:;  // fall through
2567         }
2568         [[fallthrough]];
2569       }
2570       case IN_CELL: {
2571         switch (group) {
2572           case TD_OR_TH: {
2573             eltPos = findLastInTableScope(name);
2574             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2575               errStrayEndTag(name);
2576               NS_HTML5_BREAK(endtagloop);
2577             }
2578             generateImpliedEndTags();
2579             if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2580               errUnclosedElements(eltPos, name);
2581             }
2582             while (currentPtr >= eltPos) {
2583               pop();
2584             }
2585             clearTheListOfActiveFormattingElementsUpToTheLastMarker();
2586             mode = IN_ROW;
2587             NS_HTML5_BREAK(endtagloop);
2588           }
2589           case TABLE:
2590           case TBODY_OR_THEAD_OR_TFOOT:
2591           case TR: {
2592             if (findLastInTableScope(name) ==
2593                 nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2594               MOZ_ASSERT(name == nsGkAtoms::tbody || name == nsGkAtoms::tfoot ||
2595                          name == nsGkAtoms::thead || fragment ||
2596                          isTemplateContents());
2597               errStrayEndTag(name);
2598               NS_HTML5_BREAK(endtagloop);
2599             }
2600             closeTheCell(findLastInTableScopeTdTh());
2601             continue;
2602           }
2603           case BODY:
2604           case CAPTION:
2605           case COL:
2606           case COLGROUP:
2607           case HTML: {
2608             errStrayEndTag(name);
2609             NS_HTML5_BREAK(endtagloop);
2610           }
2611           default:;  // fall through
2612         }
2613         [[fallthrough]];
2614       }
2615       case FRAMESET_OK:
2616       case IN_BODY: {
2617         switch (group) {
2618           case BODY: {
2619             if (!isSecondOnStackBody()) {
2620               MOZ_ASSERT(fragment || isTemplateContents());
2621               errStrayEndTag(name);
2622               NS_HTML5_BREAK(endtagloop);
2623             }
2624             MOZ_ASSERT(currentPtr >= 1);
2625             if (MOZ_UNLIKELY(mViewSource)) {
2626               for (int32_t i = 2; i <= currentPtr; i++) {
2627                 switch (stack[i]->getGroup()) {
2628                   case DD_OR_DT:
2629                   case LI:
2630                   case OPTGROUP:
2631                   case OPTION:
2632                   case P:
2633                   case RB_OR_RTC:
2634                   case RT_OR_RP:
2635                   case TD_OR_TH:
2636                   case TBODY_OR_THEAD_OR_TFOOT: {
2637                     break;
2638                   }
2639                   default: {
2640                     errEndWithUnclosedElements(name);
2641                     NS_HTML5_BREAK(uncloseloop1);
2642                   }
2643                 }
2644               }
2645             uncloseloop1_end:;
2646             }
2647             mode = AFTER_BODY;
2648             NS_HTML5_BREAK(endtagloop);
2649           }
2650           case HTML: {
2651             if (!isSecondOnStackBody()) {
2652               MOZ_ASSERT(fragment || isTemplateContents());
2653               errStrayEndTag(name);
2654               NS_HTML5_BREAK(endtagloop);
2655             }
2656             if (MOZ_UNLIKELY(mViewSource)) {
2657               for (int32_t i = 0; i <= currentPtr; i++) {
2658                 switch (stack[i]->getGroup()) {
2659                   case DD_OR_DT:
2660                   case LI:
2661                   case P:
2662                   case RB_OR_RTC:
2663                   case RT_OR_RP:
2664                   case TBODY_OR_THEAD_OR_TFOOT:
2665                   case TD_OR_TH:
2666                   case BODY:
2667                   case HTML: {
2668                     break;
2669                   }
2670                   default: {
2671                     errEndWithUnclosedElements(name);
2672                     NS_HTML5_BREAK(uncloseloop2);
2673                   }
2674                 }
2675               }
2676             uncloseloop2_end:;
2677             }
2678             mode = AFTER_BODY;
2679             continue;
2680           }
2681           case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
2682           case UL_OR_OL_OR_DL:
2683           case PRE_OR_LISTING:
2684           case FIELDSET:
2685           case BUTTON:
2686           case ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY: {
2687             eltPos = findLastInScope(name);
2688             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2689               errStrayEndTag(name);
2690             } else {
2691               generateImpliedEndTags();
2692               if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2693                 errUnclosedElements(eltPos, name);
2694               }
2695               while (currentPtr >= eltPos) {
2696                 pop();
2697               }
2698             }
2699             NS_HTML5_BREAK(endtagloop);
2700           }
2701           case FORM: {
2702             if (!isTemplateContents()) {
2703               if (!formPointer) {
2704                 errStrayEndTag(name);
2705                 NS_HTML5_BREAK(endtagloop);
2706               }
2707               formPointer = nullptr;
2708               eltPos = findLastInScope(name);
2709               if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2710                 errStrayEndTag(name);
2711                 NS_HTML5_BREAK(endtagloop);
2712               }
2713               generateImpliedEndTags();
2714               if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2715                 errUnclosedElements(eltPos, name);
2716               }
2717               removeFromStack(eltPos);
2718               NS_HTML5_BREAK(endtagloop);
2719             } else {
2720               eltPos = findLastInScope(name);
2721               if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2722                 errStrayEndTag(name);
2723                 NS_HTML5_BREAK(endtagloop);
2724               }
2725               generateImpliedEndTags();
2726               if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2727                 errUnclosedElements(eltPos, name);
2728               }
2729               while (currentPtr >= eltPos) {
2730                 pop();
2731               }
2732               NS_HTML5_BREAK(endtagloop);
2733             }
2734           }
2735           case P: {
2736             eltPos = findLastInButtonScope(nsGkAtoms::p);
2737             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2738               errNoElementToCloseButEndTagSeen(nsGkAtoms::p);
2739               if (isInForeign()) {
2740                 errHtmlStartTagInForeignContext(name);
2741                 while (currentPtr >= 0 &&
2742                        stack[currentPtr]->ns != kNameSpaceID_XHTML) {
2743                   pop();
2744                 }
2745               }
2746               appendVoidElementToCurrentMayFoster(
2747                   elementName, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
2748               NS_HTML5_BREAK(endtagloop);
2749             }
2750             generateImpliedEndTagsExceptFor(nsGkAtoms::p);
2751             MOZ_ASSERT(eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK);
2752             if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
2753               errUnclosedElements(eltPos, name);
2754             }
2755             while (currentPtr >= eltPos) {
2756               pop();
2757             }
2758             NS_HTML5_BREAK(endtagloop);
2759           }
2760           case LI: {
2761             eltPos = findLastInListScope(name);
2762             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2763               errNoElementToCloseButEndTagSeen(name);
2764             } else {
2765               generateImpliedEndTagsExceptFor(name);
2766               if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
2767                 errUnclosedElements(eltPos, name);
2768               }
2769               while (currentPtr >= eltPos) {
2770                 pop();
2771               }
2772             }
2773             NS_HTML5_BREAK(endtagloop);
2774           }
2775           case DD_OR_DT: {
2776             eltPos = findLastInScope(name);
2777             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2778               errNoElementToCloseButEndTagSeen(name);
2779             } else {
2780               generateImpliedEndTagsExceptFor(name);
2781               if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
2782                 errUnclosedElements(eltPos, name);
2783               }
2784               while (currentPtr >= eltPos) {
2785                 pop();
2786               }
2787             }
2788             NS_HTML5_BREAK(endtagloop);
2789           }
2790           case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: {
2791             eltPos = findLastInScopeHn();
2792             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2793               errStrayEndTag(name);
2794             } else {
2795               generateImpliedEndTags();
2796               if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2797                 errUnclosedElements(eltPos, name);
2798               }
2799               while (currentPtr >= eltPos) {
2800                 pop();
2801               }
2802             }
2803             NS_HTML5_BREAK(endtagloop);
2804           }
2805           case OBJECT:
2806           case MARQUEE_OR_APPLET: {
2807             eltPos = findLastInScope(name);
2808             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2809               errStrayEndTag(name);
2810             } else {
2811               generateImpliedEndTags();
2812               if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2813                 errUnclosedElements(eltPos, name);
2814               }
2815               while (currentPtr >= eltPos) {
2816                 pop();
2817               }
2818               clearTheListOfActiveFormattingElementsUpToTheLastMarker();
2819             }
2820             NS_HTML5_BREAK(endtagloop);
2821           }
2822           case BR: {
2823             errEndTagBr();
2824             if (isInForeign()) {
2825               errHtmlStartTagInForeignContext(name);
2826               while (currentPtr >= 0 &&
2827                      stack[currentPtr]->ns != kNameSpaceID_XHTML) {
2828                 pop();
2829               }
2830             }
2831             reconstructTheActiveFormattingElements();
2832             appendVoidElementToCurrentMayFoster(
2833                 elementName, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
2834             NS_HTML5_BREAK(endtagloop);
2835           }
2836           case TEMPLATE: {
2837             break;
2838           }
2839           case AREA_OR_WBR:
2840           case KEYGEN:
2841 #ifdef ENABLE_VOID_MENUITEM
2842           case MENUITEM:
2843 #endif
2844           case PARAM_OR_SOURCE_OR_TRACK:
2845           case EMBED:
2846           case IMG:
2847           case IMAGE:
2848           case INPUT:
2849           case HR:
2850           case IFRAME:
2851           case NOEMBED:
2852           case NOFRAMES:
2853           case SELECT:
2854           case TABLE:
2855           case TEXTAREA: {
2856             errStrayEndTag(name);
2857             NS_HTML5_BREAK(endtagloop);
2858           }
2859           case NOSCRIPT: {
2860             if (scriptingEnabled) {
2861               errStrayEndTag(name);
2862               NS_HTML5_BREAK(endtagloop);
2863             }
2864             [[fallthrough]];
2865           }
2866           case A:
2867           case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
2868           case FONT:
2869           case NOBR: {
2870             if (adoptionAgencyEndTag(name)) {
2871               NS_HTML5_BREAK(endtagloop);
2872             }
2873             [[fallthrough]];
2874           }
2875           default: {
2876             if (isCurrent(name)) {
2877               pop();
2878               NS_HTML5_BREAK(endtagloop);
2879             }
2880             eltPos = currentPtr;
2881             for (;;) {
2882               nsHtml5StackNode* node = stack[eltPos];
2883               if (node->ns == kNameSpaceID_XHTML && node->name == name) {
2884                 generateImpliedEndTags();
2885                 if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
2886                   errUnclosedElements(eltPos, name);
2887                 }
2888                 while (currentPtr >= eltPos) {
2889                   pop();
2890                 }
2891                 NS_HTML5_BREAK(endtagloop);
2892               } else if (!eltPos || node->isSpecial()) {
2893                 errStrayEndTag(name);
2894                 NS_HTML5_BREAK(endtagloop);
2895               }
2896               eltPos--;
2897             }
2898           }
2899         }
2900         [[fallthrough]];
2901       }
2902       case IN_HEAD: {
2903         switch (group) {
2904           case HEAD: {
2905             pop();
2906             mode = AFTER_HEAD;
2907             NS_HTML5_BREAK(endtagloop);
2908           }
2909           case BR:
2910           case HTML:
2911           case BODY: {
2912             pop();
2913             mode = AFTER_HEAD;
2914             continue;
2915           }
2916           case TEMPLATE: {
2917             endTagTemplateInHead();
2918             NS_HTML5_BREAK(endtagloop);
2919           }
2920           default: {
2921             errStrayEndTag(name);
2922             NS_HTML5_BREAK(endtagloop);
2923           }
2924         }
2925       }
2926       case IN_HEAD_NOSCRIPT: {
2927         switch (group) {
2928           case NOSCRIPT: {
2929             pop();
2930             mode = IN_HEAD;
2931             NS_HTML5_BREAK(endtagloop);
2932           }
2933           case BR: {
2934             errStrayEndTag(name);
2935             pop();
2936             mode = IN_HEAD;
2937             continue;
2938           }
2939           default: {
2940             errStrayEndTag(name);
2941             NS_HTML5_BREAK(endtagloop);
2942           }
2943         }
2944       }
2945       case IN_COLUMN_GROUP: {
2946         switch (group) {
2947           case COLGROUP: {
2948             if (!currentPtr ||
2949                 stack[currentPtr]->getGroup() == nsHtml5TreeBuilder::TEMPLATE) {
2950               MOZ_ASSERT(fragment || isTemplateContents());
2951               errGarbageInColgroup();
2952               NS_HTML5_BREAK(endtagloop);
2953             }
2954             pop();
2955             mode = IN_TABLE;
2956             NS_HTML5_BREAK(endtagloop);
2957           }
2958           case COL: {
2959             errStrayEndTag(name);
2960             NS_HTML5_BREAK(endtagloop);
2961           }
2962           case TEMPLATE: {
2963             endTagTemplateInHead();
2964             NS_HTML5_BREAK(endtagloop);
2965           }
2966           default: {
2967             if (!currentPtr ||
2968                 stack[currentPtr]->getGroup() == nsHtml5TreeBuilder::TEMPLATE) {
2969               MOZ_ASSERT(fragment || isTemplateContents());
2970               errGarbageInColgroup();
2971               NS_HTML5_BREAK(endtagloop);
2972             }
2973             pop();
2974             mode = IN_TABLE;
2975             continue;
2976           }
2977         }
2978       }
2979       case IN_SELECT_IN_TABLE: {
2980         switch (group) {
2981           case CAPTION:
2982           case TABLE:
2983           case TBODY_OR_THEAD_OR_TFOOT:
2984           case TR:
2985           case TD_OR_TH: {
2986             errEndTagSeenWithSelectOpen(name);
2987             if (findLastInTableScope(name) !=
2988                 nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2989               eltPos = findLastInTableScope(nsGkAtoms::select);
2990               if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
2991                 MOZ_ASSERT(fragment);
2992                 NS_HTML5_BREAK(endtagloop);
2993               }
2994               while (currentPtr >= eltPos) {
2995                 pop();
2996               }
2997               resetTheInsertionMode();
2998               continue;
2999             } else {
3000               NS_HTML5_BREAK(endtagloop);
3001             }
3002           }
3003           default:;  // fall through
3004         }
3005         [[fallthrough]];
3006       }
3007       case IN_SELECT: {
3008         switch (group) {
3009           case OPTION: {
3010             if (isCurrent(nsGkAtoms::option)) {
3011               pop();
3012               NS_HTML5_BREAK(endtagloop);
3013             } else {
3014               errStrayEndTag(name);
3015               NS_HTML5_BREAK(endtagloop);
3016             }
3017           }
3018           case OPTGROUP: {
3019             if (isCurrent(nsGkAtoms::option) &&
3020                 nsGkAtoms::optgroup == stack[currentPtr - 1]->name) {
3021               pop();
3022             }
3023             if (isCurrent(nsGkAtoms::optgroup)) {
3024               pop();
3025             } else {
3026               errStrayEndTag(name);
3027             }
3028             NS_HTML5_BREAK(endtagloop);
3029           }
3030           case SELECT: {
3031             eltPos = findLastInTableScope(nsGkAtoms::select);
3032             if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
3033               MOZ_ASSERT(fragment);
3034               errStrayEndTag(name);
3035               NS_HTML5_BREAK(endtagloop);
3036             }
3037             while (currentPtr >= eltPos) {
3038               pop();
3039             }
3040             resetTheInsertionMode();
3041             NS_HTML5_BREAK(endtagloop);
3042           }
3043           case TEMPLATE: {
3044             endTagTemplateInHead();
3045             NS_HTML5_BREAK(endtagloop);
3046           }
3047           default: {
3048             errStrayEndTag(name);
3049             NS_HTML5_BREAK(endtagloop);
3050           }
3051         }
3052       }
3053       case AFTER_BODY: {
3054         switch (group) {
3055           case HTML: {
3056             if (fragment) {
3057               errStrayEndTag(name);
3058               NS_HTML5_BREAK(endtagloop);
3059             } else {
3060               mode = AFTER_AFTER_BODY;
3061               NS_HTML5_BREAK(endtagloop);
3062             }
3063           }
3064           default: {
3065             errEndTagAfterBody();
3066             mode = framesetOk ? FRAMESET_OK : IN_BODY;
3067             continue;
3068           }
3069         }
3070       }
3071       case IN_FRAMESET: {
3072         switch (group) {
3073           case FRAMESET: {
3074             if (!currentPtr) {
3075               MOZ_ASSERT(fragment);
3076               errStrayEndTag(name);
3077               NS_HTML5_BREAK(endtagloop);
3078             }
3079             pop();
3080             if ((!fragment) && !isCurrent(nsGkAtoms::frameset)) {
3081               mode = AFTER_FRAMESET;
3082             }
3083             NS_HTML5_BREAK(endtagloop);
3084           }
3085           default: {
3086             errStrayEndTag(name);
3087             NS_HTML5_BREAK(endtagloop);
3088           }
3089         }
3090       }
3091       case AFTER_FRAMESET: {
3092         switch (group) {
3093           case HTML: {
3094             mode = AFTER_AFTER_FRAMESET;
3095             NS_HTML5_BREAK(endtagloop);
3096           }
3097           default: {
3098             errStrayEndTag(name);
3099             NS_HTML5_BREAK(endtagloop);
3100           }
3101         }
3102       }
3103       case INITIAL: {
3104         errEndTagSeenWithoutDoctype();
3105         documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
3106         mode = BEFORE_HTML;
3107         continue;
3108       }
3109       case BEFORE_HTML: {
3110         switch (group) {
3111           case HEAD:
3112           case BR:
3113           case HTML:
3114           case BODY: {
3115             appendHtmlElementToDocumentAndPush();
3116             mode = BEFORE_HEAD;
3117             continue;
3118           }
3119           default: {
3120             errStrayEndTag(name);
3121             NS_HTML5_BREAK(endtagloop);
3122           }
3123         }
3124       }
3125       case BEFORE_HEAD: {
3126         switch (group) {
3127           case HEAD:
3128           case BR:
3129           case HTML:
3130           case BODY: {
3131             appendToCurrentNodeAndPushHeadElement(
3132                 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
3133             mode = IN_HEAD;
3134             continue;
3135           }
3136           default: {
3137             errStrayEndTag(name);
3138             NS_HTML5_BREAK(endtagloop);
3139           }
3140         }
3141       }
3142       case AFTER_HEAD: {
3143         switch (group) {
3144           case TEMPLATE: {
3145             endTagTemplateInHead();
3146             NS_HTML5_BREAK(endtagloop);
3147           }
3148           case HTML:
3149           case BODY:
3150           case BR: {
3151             appendToCurrentNodeAndPushBodyElement();
3152             mode = FRAMESET_OK;
3153             continue;
3154           }
3155           default: {
3156             errStrayEndTag(name);
3157             NS_HTML5_BREAK(endtagloop);
3158           }
3159         }
3160       }
3161       case AFTER_AFTER_BODY: {
3162         errStrayEndTag(name);
3163         mode = framesetOk ? FRAMESET_OK : IN_BODY;
3164         continue;
3165       }
3166       case AFTER_AFTER_FRAMESET: {
3167         errStrayEndTag(name);
3168         NS_HTML5_BREAK(endtagloop);
3169       }
3170       case TEXT: {
3171         pop();
3172         if (originalMode == AFTER_HEAD) {
3173           silentPop();
3174         }
3175         mode = originalMode;
3176         NS_HTML5_BREAK(endtagloop);
3177       }
3178     }
3179   }
3180 endtagloop_end:;
3181 }
3182 
endTagTemplateInHead()3183 void nsHtml5TreeBuilder::endTagTemplateInHead() {
3184   int32_t eltPos = findLast(nsGkAtoms::_template);
3185   if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
3186     errStrayEndTag(nsGkAtoms::_template);
3187     return;
3188   }
3189   generateImpliedEndTagsThoroughly();
3190   if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(nsGkAtoms::_template)) {
3191     errUnclosedElements(eltPos, nsGkAtoms::_template);
3192   }
3193   while (currentPtr >= eltPos) {
3194     pop();
3195   }
3196   clearTheListOfActiveFormattingElementsUpToTheLastMarker();
3197   popTemplateMode();
3198   resetTheInsertionMode();
3199 }
3200 
3201 int32_t
findLastInTableScopeOrRootTemplateTbodyTheadTfoot()3202 nsHtml5TreeBuilder::findLastInTableScopeOrRootTemplateTbodyTheadTfoot() {
3203   for (int32_t i = currentPtr; i > 0; i--) {
3204     if (stack[i]->ns == kNameSpaceID_XHTML &&
3205         (stack[i]->getGroup() == nsHtml5TreeBuilder::TBODY_OR_THEAD_OR_TFOOT ||
3206          stack[i]->getGroup() == nsHtml5TreeBuilder::TEMPLATE)) {
3207       return i;
3208     }
3209   }
3210   return 0;
3211 }
3212 
findLast(nsAtom * name)3213 int32_t nsHtml5TreeBuilder::findLast(nsAtom* name) {
3214   for (int32_t i = currentPtr; i > 0; i--) {
3215     if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) {
3216       return i;
3217     }
3218   }
3219   return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3220 }
3221 
findLastInTableScope(nsAtom * name)3222 int32_t nsHtml5TreeBuilder::findLastInTableScope(nsAtom* name) {
3223   for (int32_t i = currentPtr; i > 0; i--) {
3224     if (stack[i]->ns == kNameSpaceID_XHTML) {
3225       if (stack[i]->name == name) {
3226         return i;
3227       } else if (stack[i]->name == nsGkAtoms::table ||
3228                  stack[i]->name == nsGkAtoms::_template) {
3229         return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3230       }
3231     }
3232   }
3233   return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3234 }
3235 
findLastInButtonScope(nsAtom * name)3236 int32_t nsHtml5TreeBuilder::findLastInButtonScope(nsAtom* name) {
3237   for (int32_t i = currentPtr; i > 0; i--) {
3238     if (stack[i]->ns == kNameSpaceID_XHTML) {
3239       if (stack[i]->name == name) {
3240         return i;
3241       } else if (stack[i]->name == nsGkAtoms::button) {
3242         return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3243       }
3244     }
3245     if (stack[i]->isScoping()) {
3246       return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3247     }
3248   }
3249   return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3250 }
3251 
findLastInScope(nsAtom * name)3252 int32_t nsHtml5TreeBuilder::findLastInScope(nsAtom* name) {
3253   for (int32_t i = currentPtr; i > 0; i--) {
3254     if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) {
3255       return i;
3256     } else if (stack[i]->isScoping()) {
3257       return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3258     }
3259   }
3260   return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3261 }
3262 
findLastInListScope(nsAtom * name)3263 int32_t nsHtml5TreeBuilder::findLastInListScope(nsAtom* name) {
3264   for (int32_t i = currentPtr; i > 0; i--) {
3265     if (stack[i]->ns == kNameSpaceID_XHTML) {
3266       if (stack[i]->name == name) {
3267         return i;
3268       } else if (stack[i]->name == nsGkAtoms::ul ||
3269                  stack[i]->name == nsGkAtoms::ol) {
3270         return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3271       }
3272     }
3273     if (stack[i]->isScoping()) {
3274       return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3275     }
3276   }
3277   return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3278 }
3279 
findLastInScopeHn()3280 int32_t nsHtml5TreeBuilder::findLastInScopeHn() {
3281   for (int32_t i = currentPtr; i > 0; i--) {
3282     if (stack[i]->getGroup() ==
3283         nsHtml5TreeBuilder::H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
3284       return i;
3285     } else if (stack[i]->isScoping()) {
3286       return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3287     }
3288   }
3289   return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3290 }
3291 
generateImpliedEndTagsExceptFor(nsAtom * name)3292 void nsHtml5TreeBuilder::generateImpliedEndTagsExceptFor(nsAtom* name) {
3293   for (;;) {
3294     nsHtml5StackNode* node = stack[currentPtr];
3295     switch (node->getGroup()) {
3296       case P:
3297       case LI:
3298       case DD_OR_DT:
3299       case OPTION:
3300       case OPTGROUP:
3301       case RB_OR_RTC:
3302       case RT_OR_RP: {
3303         if (node->ns == kNameSpaceID_XHTML && node->name == name) {
3304           return;
3305         }
3306         pop();
3307         continue;
3308       }
3309       default: {
3310         return;
3311       }
3312     }
3313   }
3314 }
3315 
generateImpliedEndTags()3316 void nsHtml5TreeBuilder::generateImpliedEndTags() {
3317   for (;;) {
3318     switch (stack[currentPtr]->getGroup()) {
3319       case P:
3320       case LI:
3321       case DD_OR_DT:
3322       case OPTION:
3323       case OPTGROUP:
3324       case RB_OR_RTC:
3325       case RT_OR_RP: {
3326         pop();
3327         continue;
3328       }
3329       default: {
3330         return;
3331       }
3332     }
3333   }
3334 }
3335 
generateImpliedEndTagsThoroughly()3336 void nsHtml5TreeBuilder::generateImpliedEndTagsThoroughly() {
3337   for (;;) {
3338     switch (stack[currentPtr]->getGroup()) {
3339       case CAPTION:
3340       case COLGROUP:
3341       case DD_OR_DT:
3342       case LI:
3343       case OPTGROUP:
3344       case OPTION:
3345       case P:
3346       case RB_OR_RTC:
3347       case RT_OR_RP:
3348       case TBODY_OR_THEAD_OR_TFOOT:
3349       case TD_OR_TH:
3350       case TR: {
3351         pop();
3352         continue;
3353       }
3354       default: {
3355         return;
3356       }
3357     }
3358   }
3359 }
3360 
isSecondOnStackBody()3361 bool nsHtml5TreeBuilder::isSecondOnStackBody() {
3362   return currentPtr >= 1 && stack[1]->getGroup() == nsHtml5TreeBuilder::BODY;
3363 }
3364 
documentModeInternal(nsHtml5DocumentMode m,nsHtml5String publicIdentifier,nsHtml5String systemIdentifier)3365 void nsHtml5TreeBuilder::documentModeInternal(nsHtml5DocumentMode m,
3366                                               nsHtml5String publicIdentifier,
3367                                               nsHtml5String systemIdentifier) {
3368   if (forceNoQuirks) {
3369     quirks = false;
3370     this->documentMode(STANDARDS_MODE);
3371     return;
3372   }
3373   quirks = (m == QUIRKS_MODE);
3374   this->documentMode(m);
3375 }
3376 
isAlmostStandards(nsHtml5String publicIdentifier,nsHtml5String systemIdentifier)3377 bool nsHtml5TreeBuilder::isAlmostStandards(nsHtml5String publicIdentifier,
3378                                            nsHtml5String systemIdentifier) {
3379   if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3380           "-//w3c//dtd xhtml 1.0 transitional//", publicIdentifier)) {
3381     return true;
3382   }
3383   if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3384           "-//w3c//dtd xhtml 1.0 frameset//", publicIdentifier)) {
3385     return true;
3386   }
3387   if (systemIdentifier) {
3388     if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3389             "-//w3c//dtd html 4.01 transitional//", publicIdentifier)) {
3390       return true;
3391     }
3392     if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3393             "-//w3c//dtd html 4.01 frameset//", publicIdentifier)) {
3394       return true;
3395     }
3396   }
3397   return false;
3398 }
3399 
isQuirky(nsAtom * name,nsHtml5String publicIdentifier,nsHtml5String systemIdentifier,bool forceQuirks)3400 bool nsHtml5TreeBuilder::isQuirky(nsAtom* name, nsHtml5String publicIdentifier,
3401                                   nsHtml5String systemIdentifier,
3402                                   bool forceQuirks) {
3403   if (forceQuirks) {
3404     return true;
3405   }
3406   if (name != nsGkAtoms::html) {
3407     return true;
3408   }
3409   if (publicIdentifier) {
3410     for (int32_t i = 0; i < nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS.length; i++) {
3411       if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3412               nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS[i], publicIdentifier)) {
3413         return true;
3414       }
3415     }
3416     if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
3417             "-//w3o//dtd w3 html strict 3.0//en//", publicIdentifier) ||
3418         nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
3419             "-/w3c/dtd html 4.0 transitional/en", publicIdentifier) ||
3420         nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
3421             "html", publicIdentifier)) {
3422       return true;
3423     }
3424   }
3425   if (!systemIdentifier) {
3426     if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3427             "-//w3c//dtd html 4.01 transitional//", publicIdentifier)) {
3428       return true;
3429     } else if (nsHtml5Portability::
3430                    lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
3431                        "-//w3c//dtd html 4.01 frameset//", publicIdentifier)) {
3432       return true;
3433     }
3434   } else if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
3435                  "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd",
3436                  systemIdentifier)) {
3437     return true;
3438   }
3439   return false;
3440 }
3441 
closeTheCell(int32_t eltPos)3442 void nsHtml5TreeBuilder::closeTheCell(int32_t eltPos) {
3443   generateImpliedEndTags();
3444   if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
3445     errUnclosedElementsCell(eltPos);
3446   }
3447   while (currentPtr >= eltPos) {
3448     pop();
3449   }
3450   clearTheListOfActiveFormattingElementsUpToTheLastMarker();
3451   mode = IN_ROW;
3452   return;
3453 }
3454 
findLastInTableScopeTdTh()3455 int32_t nsHtml5TreeBuilder::findLastInTableScopeTdTh() {
3456   for (int32_t i = currentPtr; i > 0; i--) {
3457     nsAtom* name = stack[i]->name;
3458     if (stack[i]->ns == kNameSpaceID_XHTML) {
3459       if (nsGkAtoms::td == name || nsGkAtoms::th == name) {
3460         return i;
3461       } else if (name == nsGkAtoms::table || name == nsGkAtoms::_template) {
3462         return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3463       }
3464     }
3465   }
3466   return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
3467 }
3468 
clearStackBackTo(int32_t eltPos)3469 void nsHtml5TreeBuilder::clearStackBackTo(int32_t eltPos) {
3470   int32_t eltGroup = stack[eltPos]->getGroup();
3471   while (currentPtr > eltPos) {
3472     if (stack[currentPtr]->ns == kNameSpaceID_XHTML &&
3473         stack[currentPtr]->getGroup() == TEMPLATE &&
3474         (eltGroup == TABLE || eltGroup == TBODY_OR_THEAD_OR_TFOOT ||
3475          eltGroup == TR || !eltPos)) {
3476       return;
3477     }
3478     pop();
3479   }
3480 }
3481 
resetTheInsertionMode()3482 void nsHtml5TreeBuilder::resetTheInsertionMode() {
3483   nsHtml5StackNode* node;
3484   nsAtom* name;
3485   int32_t ns;
3486   for (int32_t i = currentPtr; i >= 0; i--) {
3487     node = stack[i];
3488     name = node->name;
3489     ns = node->ns;
3490     if (!i) {
3491       if (!(contextNamespace == kNameSpaceID_XHTML &&
3492             (contextName == nsGkAtoms::td || contextName == nsGkAtoms::th))) {
3493         if (fragment) {
3494           name = contextName;
3495           ns = contextNamespace;
3496         }
3497       } else {
3498         mode = framesetOk ? FRAMESET_OK : IN_BODY;
3499         return;
3500       }
3501     }
3502     if (nsGkAtoms::select == name) {
3503       int32_t ancestorIndex = i;
3504       while (ancestorIndex > 0) {
3505         nsHtml5StackNode* ancestor = stack[ancestorIndex--];
3506         if (kNameSpaceID_XHTML == ancestor->ns) {
3507           if (nsGkAtoms::_template == ancestor->name) {
3508             break;
3509           }
3510           if (nsGkAtoms::table == ancestor->name) {
3511             mode = IN_SELECT_IN_TABLE;
3512             return;
3513           }
3514         }
3515       }
3516       mode = IN_SELECT;
3517       return;
3518     } else if (nsGkAtoms::td == name || nsGkAtoms::th == name) {
3519       mode = IN_CELL;
3520       return;
3521     } else if (nsGkAtoms::tr == name) {
3522       mode = IN_ROW;
3523       return;
3524     } else if (nsGkAtoms::tbody == name || nsGkAtoms::thead == name ||
3525                nsGkAtoms::tfoot == name) {
3526       mode = IN_TABLE_BODY;
3527       return;
3528     } else if (nsGkAtoms::caption == name) {
3529       mode = IN_CAPTION;
3530       return;
3531     } else if (nsGkAtoms::colgroup == name) {
3532       mode = IN_COLUMN_GROUP;
3533       return;
3534     } else if (nsGkAtoms::table == name) {
3535       mode = IN_TABLE;
3536       return;
3537     } else if (kNameSpaceID_XHTML != ns) {
3538       mode = framesetOk ? FRAMESET_OK : IN_BODY;
3539       return;
3540     } else if (nsGkAtoms::_template == name) {
3541       MOZ_ASSERT(templateModePtr >= 0);
3542       mode = templateModeStack[templateModePtr];
3543       return;
3544     } else if (nsGkAtoms::head == name) {
3545       if (name == contextName) {
3546         mode = framesetOk ? FRAMESET_OK : IN_BODY;
3547       } else {
3548         mode = IN_HEAD;
3549       }
3550       return;
3551     } else if (nsGkAtoms::body == name) {
3552       mode = framesetOk ? FRAMESET_OK : IN_BODY;
3553       return;
3554     } else if (nsGkAtoms::frameset == name) {
3555       mode = IN_FRAMESET;
3556       return;
3557     } else if (nsGkAtoms::html == name) {
3558       if (!headPointer) {
3559         mode = BEFORE_HEAD;
3560       } else {
3561         mode = AFTER_HEAD;
3562       }
3563       return;
3564     } else if (!i) {
3565       mode = framesetOk ? FRAMESET_OK : IN_BODY;
3566       return;
3567     }
3568   }
3569 }
3570 
implicitlyCloseP()3571 void nsHtml5TreeBuilder::implicitlyCloseP() {
3572   int32_t eltPos = findLastInButtonScope(nsGkAtoms::p);
3573   if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
3574     return;
3575   }
3576   generateImpliedEndTagsExceptFor(nsGkAtoms::p);
3577   if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
3578     errUnclosedElementsImplied(eltPos, nsGkAtoms::p);
3579   }
3580   while (currentPtr >= eltPos) {
3581     pop();
3582   }
3583 }
3584 
debugOnlyClearLastStackSlot()3585 bool nsHtml5TreeBuilder::debugOnlyClearLastStackSlot() {
3586   stack[currentPtr] = nullptr;
3587   return true;
3588 }
3589 
debugOnlyClearLastListSlot()3590 bool nsHtml5TreeBuilder::debugOnlyClearLastListSlot() {
3591   listOfActiveFormattingElements[listPtr] = nullptr;
3592   return true;
3593 }
3594 
pushTemplateMode(int32_t mode)3595 void nsHtml5TreeBuilder::pushTemplateMode(int32_t mode) {
3596   templateModePtr++;
3597   if (templateModePtr == templateModeStack.length) {
3598     jArray<int32_t, int32_t> newStack =
3599         jArray<int32_t, int32_t>::newJArray(templateModeStack.length + 64);
3600     nsHtml5ArrayCopy::arraycopy(templateModeStack, newStack,
3601                                 templateModeStack.length);
3602     templateModeStack = newStack;
3603   }
3604   templateModeStack[templateModePtr] = mode;
3605 }
3606 
push(nsHtml5StackNode * node)3607 void nsHtml5TreeBuilder::push(nsHtml5StackNode* node) {
3608   currentPtr++;
3609   if (currentPtr == stack.length) {
3610     jArray<nsHtml5StackNode*, int32_t> newStack =
3611         jArray<nsHtml5StackNode*, int32_t>::newJArray(stack.length + 64);
3612     nsHtml5ArrayCopy::arraycopy(stack, newStack, stack.length);
3613     stack = newStack;
3614   }
3615   stack[currentPtr] = node;
3616   elementPushed(node->ns, node->popName, node->node);
3617 }
3618 
silentPush(nsHtml5StackNode * node)3619 void nsHtml5TreeBuilder::silentPush(nsHtml5StackNode* node) {
3620   currentPtr++;
3621   if (currentPtr == stack.length) {
3622     jArray<nsHtml5StackNode*, int32_t> newStack =
3623         jArray<nsHtml5StackNode*, int32_t>::newJArray(stack.length + 64);
3624     nsHtml5ArrayCopy::arraycopy(stack, newStack, stack.length);
3625     stack = newStack;
3626   }
3627   stack[currentPtr] = node;
3628 }
3629 
append(nsHtml5StackNode * node)3630 void nsHtml5TreeBuilder::append(nsHtml5StackNode* node) {
3631   listPtr++;
3632   if (listPtr == listOfActiveFormattingElements.length) {
3633     jArray<nsHtml5StackNode*, int32_t> newList =
3634         jArray<nsHtml5StackNode*, int32_t>::newJArray(
3635             listOfActiveFormattingElements.length + 64);
3636     nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, newList,
3637                                 listOfActiveFormattingElements.length);
3638     listOfActiveFormattingElements = newList;
3639   }
3640   listOfActiveFormattingElements[listPtr] = node;
3641 }
3642 
3643 void nsHtml5TreeBuilder::
clearTheListOfActiveFormattingElementsUpToTheLastMarker()3644     clearTheListOfActiveFormattingElementsUpToTheLastMarker() {
3645   while (listPtr > -1) {
3646     if (!listOfActiveFormattingElements[listPtr]) {
3647       --listPtr;
3648       return;
3649     }
3650     listOfActiveFormattingElements[listPtr]->release(this);
3651     --listPtr;
3652   }
3653 }
3654 
removeFromStack(int32_t pos)3655 void nsHtml5TreeBuilder::removeFromStack(int32_t pos) {
3656   if (currentPtr == pos) {
3657     pop();
3658   } else {
3659     stack[pos]->release(this);
3660     nsHtml5ArrayCopy::arraycopy(stack, pos + 1, pos, currentPtr - pos);
3661     MOZ_ASSERT(debugOnlyClearLastStackSlot());
3662     currentPtr--;
3663   }
3664 }
3665 
removeFromStack(nsHtml5StackNode * node)3666 void nsHtml5TreeBuilder::removeFromStack(nsHtml5StackNode* node) {
3667   if (stack[currentPtr] == node) {
3668     pop();
3669   } else {
3670     int32_t pos = currentPtr - 1;
3671     while (pos >= 0 && stack[pos] != node) {
3672       pos--;
3673     }
3674     if (pos == -1) {
3675       return;
3676     }
3677 
3678     node->release(this);
3679     nsHtml5ArrayCopy::arraycopy(stack, pos + 1, pos, currentPtr - pos);
3680     currentPtr--;
3681   }
3682 }
3683 
removeFromListOfActiveFormattingElements(int32_t pos)3684 void nsHtml5TreeBuilder::removeFromListOfActiveFormattingElements(int32_t pos) {
3685   MOZ_ASSERT(!!listOfActiveFormattingElements[pos]);
3686   listOfActiveFormattingElements[pos]->release(this);
3687   if (pos == listPtr) {
3688     MOZ_ASSERT(debugOnlyClearLastListSlot());
3689     listPtr--;
3690     return;
3691   }
3692   MOZ_ASSERT(pos < listPtr);
3693   nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, pos + 1, pos,
3694                               listPtr - pos);
3695   MOZ_ASSERT(debugOnlyClearLastListSlot());
3696   listPtr--;
3697 }
3698 
adoptionAgencyEndTag(nsAtom * name)3699 bool nsHtml5TreeBuilder::adoptionAgencyEndTag(nsAtom* name) {
3700   if (stack[currentPtr]->ns == kNameSpaceID_XHTML &&
3701       stack[currentPtr]->name == name &&
3702       findInListOfActiveFormattingElements(stack[currentPtr]) == -1) {
3703     pop();
3704     return true;
3705   }
3706   for (int32_t i = 0; i < 8; ++i) {
3707     int32_t formattingEltListPos = listPtr;
3708     while (formattingEltListPos > -1) {
3709       nsHtml5StackNode* listNode =
3710           listOfActiveFormattingElements[formattingEltListPos];
3711       if (!listNode) {
3712         formattingEltListPos = -1;
3713         break;
3714       } else if (listNode->name == name) {
3715         break;
3716       }
3717       formattingEltListPos--;
3718     }
3719     if (formattingEltListPos == -1) {
3720       return false;
3721     }
3722     nsHtml5StackNode* formattingElt =
3723         listOfActiveFormattingElements[formattingEltListPos];
3724     int32_t formattingEltStackPos = currentPtr;
3725     bool inScope = true;
3726     while (formattingEltStackPos > -1) {
3727       nsHtml5StackNode* node = stack[formattingEltStackPos];
3728       if (node == formattingElt) {
3729         break;
3730       } else if (node->isScoping()) {
3731         inScope = false;
3732       }
3733       formattingEltStackPos--;
3734     }
3735     if (formattingEltStackPos == -1) {
3736       errNoElementToCloseButEndTagSeen(name);
3737       removeFromListOfActiveFormattingElements(formattingEltListPos);
3738       return true;
3739     }
3740     if (!inScope) {
3741       errNoElementToCloseButEndTagSeen(name);
3742       return true;
3743     }
3744     if (formattingEltStackPos != currentPtr) {
3745       errEndTagViolatesNestingRules(name);
3746     }
3747     int32_t furthestBlockPos = formattingEltStackPos + 1;
3748     while (furthestBlockPos <= currentPtr) {
3749       nsHtml5StackNode* node = stack[furthestBlockPos];
3750       MOZ_ASSERT(furthestBlockPos > 0,
3751                  "How is formattingEltStackPos + 1 not > 0?");
3752       if (node->isSpecial()) {
3753         break;
3754       }
3755       furthestBlockPos++;
3756     }
3757     if (furthestBlockPos > currentPtr) {
3758       while (currentPtr >= formattingEltStackPos) {
3759         pop();
3760       }
3761       removeFromListOfActiveFormattingElements(formattingEltListPos);
3762       return true;
3763     }
3764     nsHtml5StackNode* commonAncestor = stack[formattingEltStackPos - 1];
3765     nsIContentHandle* insertionCommonAncestor =
3766         nodeFromStackWithBlinkCompat(formattingEltStackPos - 1);
3767     nsHtml5StackNode* furthestBlock = stack[furthestBlockPos];
3768     int32_t bookmark = formattingEltListPos;
3769     int32_t nodePos = furthestBlockPos;
3770     nsHtml5StackNode* lastNode = furthestBlock;
3771     int32_t j = 0;
3772     for (;;) {
3773       ++j;
3774       nodePos--;
3775       if (nodePos == formattingEltStackPos) {
3776         break;
3777       }
3778       nsHtml5StackNode* node = stack[nodePos];
3779       int32_t nodeListPos = findInListOfActiveFormattingElements(node);
3780       if (j > 3 && nodeListPos != -1) {
3781         removeFromListOfActiveFormattingElements(nodeListPos);
3782         if (nodeListPos <= formattingEltListPos) {
3783           formattingEltListPos--;
3784         }
3785         if (nodeListPos <= bookmark) {
3786           bookmark--;
3787         }
3788         nodeListPos = -1;
3789       }
3790       if (nodeListPos == -1) {
3791         MOZ_ASSERT(formattingEltStackPos < nodePos);
3792         MOZ_ASSERT(bookmark < nodePos);
3793         MOZ_ASSERT(furthestBlockPos > nodePos);
3794         removeFromStack(nodePos);
3795         furthestBlockPos--;
3796         continue;
3797       }
3798       if (nodePos == furthestBlockPos) {
3799         bookmark = nodeListPos + 1;
3800       }
3801       MOZ_ASSERT(node == listOfActiveFormattingElements[nodeListPos]);
3802       MOZ_ASSERT(node == stack[nodePos]);
3803       nsIContentHandle* clone = createElement(
3804           kNameSpaceID_XHTML, node->name, node->attributes->cloneAttributes(),
3805           insertionCommonAncestor, htmlCreator(node->getHtmlCreator()));
3806       nsHtml5StackNode* newNode = createStackNode(
3807           node->getFlags(), node->ns, node->name, clone, node->popName,
3808           node->attributes, node->getHtmlCreator());
3809       node->dropAttributes();
3810       stack[nodePos] = newNode;
3811       newNode->retain();
3812       listOfActiveFormattingElements[nodeListPos] = newNode;
3813       node->release(this);
3814       node->release(this);
3815       node = newNode;
3816       detachFromParent(lastNode->node);
3817       appendElement(lastNode->node, nodeFromStackWithBlinkCompat(nodePos));
3818       lastNode = node;
3819     }
3820     if (commonAncestor->isFosterParenting()) {
3821       detachFromParent(lastNode->node);
3822       insertIntoFosterParent(lastNode->node);
3823     } else {
3824       detachFromParent(lastNode->node);
3825       appendElement(lastNode->node, insertionCommonAncestor);
3826     }
3827     nsIContentHandle* clone = createElement(
3828         kNameSpaceID_XHTML, formattingElt->name,
3829         formattingElt->attributes->cloneAttributes(), furthestBlock->node,
3830         htmlCreator(formattingElt->getHtmlCreator()));
3831     nsHtml5StackNode* formattingClone = createStackNode(
3832         formattingElt->getFlags(), formattingElt->ns, formattingElt->name,
3833         clone, formattingElt->popName, formattingElt->attributes,
3834         formattingElt->getHtmlCreator());
3835     formattingElt->dropAttributes();
3836     appendChildrenToNewParent(furthestBlock->node, clone);
3837     appendElement(clone, furthestBlock->node);
3838     removeFromListOfActiveFormattingElements(formattingEltListPos);
3839     insertIntoListOfActiveFormattingElements(formattingClone, bookmark);
3840     MOZ_ASSERT(formattingEltStackPos < furthestBlockPos);
3841     removeFromStack(formattingEltStackPos);
3842     insertIntoStack(formattingClone, furthestBlockPos);
3843   }
3844   return true;
3845 }
3846 
insertIntoStack(nsHtml5StackNode * node,int32_t position)3847 void nsHtml5TreeBuilder::insertIntoStack(nsHtml5StackNode* node,
3848                                          int32_t position) {
3849   MOZ_ASSERT(currentPtr + 1 < stack.length);
3850   MOZ_ASSERT(position <= currentPtr + 1);
3851   if (position == currentPtr + 1) {
3852     push(node);
3853   } else {
3854     nsHtml5ArrayCopy::arraycopy(stack, position, position + 1,
3855                                 (currentPtr - position) + 1);
3856     currentPtr++;
3857     stack[position] = node;
3858   }
3859 }
3860 
insertIntoListOfActiveFormattingElements(nsHtml5StackNode * formattingClone,int32_t bookmark)3861 void nsHtml5TreeBuilder::insertIntoListOfActiveFormattingElements(
3862     nsHtml5StackNode* formattingClone, int32_t bookmark) {
3863   formattingClone->retain();
3864   MOZ_ASSERT(listPtr + 1 < listOfActiveFormattingElements.length);
3865   if (bookmark <= listPtr) {
3866     nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, bookmark,
3867                                 bookmark + 1, (listPtr - bookmark) + 1);
3868   }
3869   listPtr++;
3870   listOfActiveFormattingElements[bookmark] = formattingClone;
3871 }
3872 
findInListOfActiveFormattingElements(nsHtml5StackNode * node)3873 int32_t nsHtml5TreeBuilder::findInListOfActiveFormattingElements(
3874     nsHtml5StackNode* node) {
3875   for (int32_t i = listPtr; i >= 0; i--) {
3876     if (node == listOfActiveFormattingElements[i]) {
3877       return i;
3878     }
3879   }
3880   return -1;
3881 }
3882 
3883 int32_t nsHtml5TreeBuilder::
findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(nsAtom * name)3884     findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(
3885         nsAtom* name) {
3886   for (int32_t i = listPtr; i >= 0; i--) {
3887     nsHtml5StackNode* node = listOfActiveFormattingElements[i];
3888     if (!node) {
3889       return -1;
3890     } else if (node->name == name) {
3891       return i;
3892     }
3893   }
3894   return -1;
3895 }
3896 
maybeForgetEarlierDuplicateFormattingElement(nsAtom * name,nsHtml5HtmlAttributes * attributes)3897 void nsHtml5TreeBuilder::maybeForgetEarlierDuplicateFormattingElement(
3898     nsAtom* name, nsHtml5HtmlAttributes* attributes) {
3899   int32_t candidate = -1;
3900   int32_t count = 0;
3901   for (int32_t i = listPtr; i >= 0; i--) {
3902     nsHtml5StackNode* node = listOfActiveFormattingElements[i];
3903     if (!node) {
3904       break;
3905     }
3906     if (node->name == name && node->attributes->equalsAnother(attributes)) {
3907       candidate = i;
3908       ++count;
3909     }
3910   }
3911   if (count >= 3) {
3912     removeFromListOfActiveFormattingElements(candidate);
3913   }
3914 }
3915 
findLastOrRoot(nsAtom * name)3916 int32_t nsHtml5TreeBuilder::findLastOrRoot(nsAtom* name) {
3917   for (int32_t i = currentPtr; i > 0; i--) {
3918     if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) {
3919       return i;
3920     }
3921   }
3922   return 0;
3923 }
3924 
findLastOrRoot(int32_t group)3925 int32_t nsHtml5TreeBuilder::findLastOrRoot(int32_t group) {
3926   for (int32_t i = currentPtr; i > 0; i--) {
3927     if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->getGroup() == group) {
3928       return i;
3929     }
3930   }
3931   return 0;
3932 }
3933 
addAttributesToBody(nsHtml5HtmlAttributes * attributes)3934 bool nsHtml5TreeBuilder::addAttributesToBody(
3935     nsHtml5HtmlAttributes* attributes) {
3936   if (currentPtr >= 1) {
3937     nsHtml5StackNode* body = stack[1];
3938     if (body->getGroup() == nsHtml5TreeBuilder::BODY) {
3939       addAttributesToElement(body->node, attributes);
3940       return true;
3941     }
3942   }
3943   return false;
3944 }
3945 
addAttributesToHtml(nsHtml5HtmlAttributes * attributes)3946 void nsHtml5TreeBuilder::addAttributesToHtml(
3947     nsHtml5HtmlAttributes* attributes) {
3948   addAttributesToElement(stack[0]->node, attributes);
3949 }
3950 
pushHeadPointerOntoStack()3951 void nsHtml5TreeBuilder::pushHeadPointerOntoStack() {
3952   MOZ_ASSERT(!!headPointer);
3953   MOZ_ASSERT(mode == AFTER_HEAD);
3954 
3955   silentPush(createStackNode(nsHtml5ElementName::ELT_HEAD, headPointer));
3956 }
3957 
reconstructTheActiveFormattingElements()3958 void nsHtml5TreeBuilder::reconstructTheActiveFormattingElements() {
3959   if (listPtr == -1) {
3960     return;
3961   }
3962   nsHtml5StackNode* mostRecent = listOfActiveFormattingElements[listPtr];
3963   if (!mostRecent || isInStack(mostRecent)) {
3964     return;
3965   }
3966   int32_t entryPos = listPtr;
3967   for (;;) {
3968     entryPos--;
3969     if (entryPos == -1) {
3970       break;
3971     }
3972     if (!listOfActiveFormattingElements[entryPos]) {
3973       break;
3974     }
3975     if (isInStack(listOfActiveFormattingElements[entryPos])) {
3976       break;
3977     }
3978   }
3979   while (entryPos < listPtr) {
3980     entryPos++;
3981     nsHtml5StackNode* entry = listOfActiveFormattingElements[entryPos];
3982     nsHtml5StackNode* current = stack[currentPtr];
3983     nsIContentHandle* clone;
3984     if (current->isFosterParenting()) {
3985       clone = createAndInsertFosterParentedElement(
3986           kNameSpaceID_XHTML, entry->name, entry->attributes->cloneAttributes(),
3987           htmlCreator(entry->getHtmlCreator()));
3988     } else {
3989       nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
3990       clone = createElement(kNameSpaceID_XHTML, entry->name,
3991                             entry->attributes->cloneAttributes(), currentNode,
3992                             htmlCreator(entry->getHtmlCreator()));
3993       appendElement(clone, currentNode);
3994     }
3995     nsHtml5StackNode* entryClone = createStackNode(
3996         entry->getFlags(), entry->ns, entry->name, clone, entry->popName,
3997         entry->attributes, entry->getHtmlCreator());
3998     entry->dropAttributes();
3999     push(entryClone);
4000     listOfActiveFormattingElements[entryPos] = entryClone;
4001     entry->release(this);
4002     entryClone->retain();
4003   }
4004 }
4005 
notifyUnusedStackNode(int32_t idxInStackNodes)4006 void nsHtml5TreeBuilder::notifyUnusedStackNode(int32_t idxInStackNodes) {
4007   if (idxInStackNodes < stackNodesIdx) {
4008     stackNodesIdx = idxInStackNodes;
4009   }
4010 }
4011 
getUnusedStackNode()4012 nsHtml5StackNode* nsHtml5TreeBuilder::getUnusedStackNode() {
4013   while (stackNodesIdx < numStackNodes) {
4014     if (stackNodes[stackNodesIdx]->isUnused()) {
4015       return stackNodes[stackNodesIdx++];
4016     }
4017     stackNodesIdx++;
4018   }
4019   if (stackNodesIdx < stackNodes.length) {
4020     stackNodes[stackNodesIdx] = new nsHtml5StackNode(stackNodesIdx);
4021     numStackNodes++;
4022     return stackNodes[stackNodesIdx++];
4023   }
4024   jArray<nsHtml5StackNode*, int32_t> newStack =
4025       jArray<nsHtml5StackNode*, int32_t>::newJArray(stackNodes.length + 64);
4026   nsHtml5ArrayCopy::arraycopy(stackNodes, newStack, stackNodes.length);
4027   stackNodes = newStack;
4028   stackNodes[stackNodesIdx] = new nsHtml5StackNode(stackNodesIdx);
4029   numStackNodes++;
4030   return stackNodes[stackNodesIdx++];
4031 }
4032 
createStackNode(int32_t flags,int32_t ns,nsAtom * name,nsIContentHandle * node,nsAtom * popName,nsHtml5HtmlAttributes * attributes,mozilla::dom::HTMLContentCreatorFunction htmlCreator)4033 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4034     int32_t flags, int32_t ns, nsAtom* name, nsIContentHandle* node,
4035     nsAtom* popName, nsHtml5HtmlAttributes* attributes,
4036     mozilla::dom::HTMLContentCreatorFunction htmlCreator) {
4037   nsHtml5StackNode* instance = getUnusedStackNode();
4038   instance->setValues(flags, ns, name, node, popName, attributes, htmlCreator);
4039   return instance;
4040 }
4041 
createStackNode(nsHtml5ElementName * elementName,nsIContentHandle * node)4042 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4043     nsHtml5ElementName* elementName, nsIContentHandle* node) {
4044   nsHtml5StackNode* instance = getUnusedStackNode();
4045   instance->setValues(elementName, node);
4046   return instance;
4047 }
4048 
createStackNode(nsHtml5ElementName * elementName,nsIContentHandle * node,nsHtml5HtmlAttributes * attributes)4049 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4050     nsHtml5ElementName* elementName, nsIContentHandle* node,
4051     nsHtml5HtmlAttributes* attributes) {
4052   nsHtml5StackNode* instance = getUnusedStackNode();
4053   instance->setValues(elementName, node, attributes);
4054   return instance;
4055 }
4056 
createStackNode(nsHtml5ElementName * elementName,nsIContentHandle * node,nsAtom * popName)4057 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4058     nsHtml5ElementName* elementName, nsIContentHandle* node, nsAtom* popName) {
4059   nsHtml5StackNode* instance = getUnusedStackNode();
4060   instance->setValues(elementName, node, popName);
4061   return instance;
4062 }
4063 
createStackNode(nsHtml5ElementName * elementName,nsAtom * popName,nsIContentHandle * node)4064 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4065     nsHtml5ElementName* elementName, nsAtom* popName, nsIContentHandle* node) {
4066   nsHtml5StackNode* instance = getUnusedStackNode();
4067   instance->setValues(elementName, popName, node);
4068   return instance;
4069 }
4070 
createStackNode(nsHtml5ElementName * elementName,nsIContentHandle * node,nsAtom * popName,bool markAsIntegrationPoint)4071 nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
4072     nsHtml5ElementName* elementName, nsIContentHandle* node, nsAtom* popName,
4073     bool markAsIntegrationPoint) {
4074   nsHtml5StackNode* instance = getUnusedStackNode();
4075   instance->setValues(elementName, node, popName, markAsIntegrationPoint);
4076   return instance;
4077 }
4078 
insertIntoFosterParent(nsIContentHandle * child)4079 void nsHtml5TreeBuilder::insertIntoFosterParent(nsIContentHandle* child) {
4080   int32_t tablePos = findLastOrRoot(nsHtml5TreeBuilder::TABLE);
4081   int32_t templatePos = findLastOrRoot(nsHtml5TreeBuilder::TEMPLATE);
4082   if (templatePos >= tablePos) {
4083     appendElement(child, stack[templatePos]->node);
4084     return;
4085   }
4086   nsHtml5StackNode* node = stack[tablePos];
4087   insertFosterParentedChild(child, node->node, stack[tablePos - 1]->node);
4088 }
4089 
createAndInsertFosterParentedElement(int32_t ns,nsAtom * name,nsHtml5HtmlAttributes * attributes,nsHtml5ContentCreatorFunction creator)4090 nsIContentHandle* nsHtml5TreeBuilder::createAndInsertFosterParentedElement(
4091     int32_t ns, nsAtom* name, nsHtml5HtmlAttributes* attributes,
4092     nsHtml5ContentCreatorFunction creator) {
4093   return createAndInsertFosterParentedElement(ns, name, attributes, nullptr,
4094                                               creator);
4095 }
4096 
createAndInsertFosterParentedElement(int32_t ns,nsAtom * name,nsHtml5HtmlAttributes * attributes,nsIContentHandle * form,nsHtml5ContentCreatorFunction creator)4097 nsIContentHandle* nsHtml5TreeBuilder::createAndInsertFosterParentedElement(
4098     int32_t ns, nsAtom* name, nsHtml5HtmlAttributes* attributes,
4099     nsIContentHandle* form, nsHtml5ContentCreatorFunction creator) {
4100   int32_t tablePos = findLastOrRoot(nsHtml5TreeBuilder::TABLE);
4101   int32_t templatePos = findLastOrRoot(nsHtml5TreeBuilder::TEMPLATE);
4102   if (templatePos >= tablePos) {
4103     nsIContentHandle* child = createElement(ns, name, attributes, form,
4104                                             stack[templatePos]->node, creator);
4105     appendElement(child, stack[templatePos]->node);
4106     return child;
4107   }
4108   nsHtml5StackNode* node = stack[tablePos];
4109   return createAndInsertFosterParentedElement(
4110       ns, name, attributes, form, node->node, stack[tablePos - 1]->node,
4111       creator);
4112 }
4113 
isInStack(nsHtml5StackNode * node)4114 bool nsHtml5TreeBuilder::isInStack(nsHtml5StackNode* node) {
4115   for (int32_t i = currentPtr; i >= 0; i--) {
4116     if (stack[i] == node) {
4117       return true;
4118     }
4119   }
4120   return false;
4121 }
4122 
popTemplateMode()4123 void nsHtml5TreeBuilder::popTemplateMode() { templateModePtr--; }
4124 
pop()4125 void nsHtml5TreeBuilder::pop() {
4126   nsHtml5StackNode* node = stack[currentPtr];
4127   MOZ_ASSERT(debugOnlyClearLastStackSlot());
4128   currentPtr--;
4129   elementPopped(node->ns, node->popName, node->node);
4130   node->release(this);
4131 }
4132 
popForeign(int32_t origPos,int32_t eltPos)4133 void nsHtml5TreeBuilder::popForeign(int32_t origPos, int32_t eltPos) {
4134   nsHtml5StackNode* node = stack[currentPtr];
4135   if (origPos != currentPtr || eltPos != currentPtr) {
4136     markMalformedIfScript(node->node);
4137   }
4138   MOZ_ASSERT(debugOnlyClearLastStackSlot());
4139   currentPtr--;
4140   elementPopped(node->ns, node->popName, node->node);
4141   node->release(this);
4142 }
4143 
silentPop()4144 void nsHtml5TreeBuilder::silentPop() {
4145   nsHtml5StackNode* node = stack[currentPtr];
4146   MOZ_ASSERT(debugOnlyClearLastStackSlot());
4147   currentPtr--;
4148   node->release(this);
4149 }
4150 
popOnEof()4151 void nsHtml5TreeBuilder::popOnEof() {
4152   nsHtml5StackNode* node = stack[currentPtr];
4153   MOZ_ASSERT(debugOnlyClearLastStackSlot());
4154   currentPtr--;
4155   markMalformedIfScript(node->node);
4156   elementPopped(node->ns, node->popName, node->node);
4157   node->release(this);
4158 }
4159 
appendHtmlElementToDocumentAndPush(nsHtml5HtmlAttributes * attributes)4160 void nsHtml5TreeBuilder::appendHtmlElementToDocumentAndPush(
4161     nsHtml5HtmlAttributes* attributes) {
4162   nsIContentHandle* elt = createHtmlElementSetAsRoot(attributes);
4163   nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_HTML, elt);
4164   push(node);
4165 }
4166 
appendHtmlElementToDocumentAndPush()4167 void nsHtml5TreeBuilder::appendHtmlElementToDocumentAndPush() {
4168   appendHtmlElementToDocumentAndPush(tokenizer->emptyAttributes());
4169 }
4170 
appendToCurrentNodeAndPushHeadElement(nsHtml5HtmlAttributes * attributes)4171 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushHeadElement(
4172     nsHtml5HtmlAttributes* attributes) {
4173   nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4174   nsIContentHandle* elt =
4175       createElement(kNameSpaceID_XHTML, nsGkAtoms::head, attributes,
4176                     currentNode, htmlCreator(NS_NewHTMLSharedElement));
4177   appendElement(elt, currentNode);
4178   headPointer = elt;
4179   nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_HEAD, elt);
4180   push(node);
4181 }
4182 
appendToCurrentNodeAndPushBodyElement(nsHtml5HtmlAttributes * attributes)4183 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushBodyElement(
4184     nsHtml5HtmlAttributes* attributes) {
4185   appendToCurrentNodeAndPushElement(nsHtml5ElementName::ELT_BODY, attributes);
4186 }
4187 
appendToCurrentNodeAndPushBodyElement()4188 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushBodyElement() {
4189   appendToCurrentNodeAndPushBodyElement(tokenizer->emptyAttributes());
4190 }
4191 
appendToCurrentNodeAndPushFormElementMayFoster(nsHtml5HtmlAttributes * attributes)4192 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormElementMayFoster(
4193     nsHtml5HtmlAttributes* attributes) {
4194   nsIContentHandle* elt;
4195   nsHtml5StackNode* current = stack[currentPtr];
4196   if (current->isFosterParenting()) {
4197     elt = createAndInsertFosterParentedElement(
4198         kNameSpaceID_XHTML, nsGkAtoms::form, attributes,
4199         htmlCreator(NS_NewHTMLFormElement));
4200   } else {
4201     nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4202     elt = createElement(kNameSpaceID_XHTML, nsGkAtoms::form, attributes,
4203                         currentNode, htmlCreator(NS_NewHTMLFormElement));
4204     appendElement(elt, currentNode);
4205   }
4206   if (!isTemplateContents()) {
4207     formPointer = elt;
4208   }
4209   nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_FORM, elt);
4210   push(node);
4211 }
4212 
appendToCurrentNodeAndPushFormattingElementMayFoster(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes)4213 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormattingElementMayFoster(
4214     nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4215   nsHtml5HtmlAttributes* clone = attributes->cloneAttributes();
4216   nsIContentHandle* elt;
4217   nsHtml5StackNode* current = stack[currentPtr];
4218   if (current->isFosterParenting()) {
4219     elt = createAndInsertFosterParentedElement(
4220         kNameSpaceID_XHTML, elementName->getName(), attributes,
4221         htmlCreator(elementName->getHtmlCreator()));
4222   } else {
4223     nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4224     elt =
4225         createElement(kNameSpaceID_XHTML, elementName->getName(), attributes,
4226                       currentNode, htmlCreator(elementName->getHtmlCreator()));
4227     appendElement(elt, currentNode);
4228   }
4229   nsHtml5StackNode* node = createStackNode(elementName, elt, clone);
4230   push(node);
4231   append(node);
4232   node->retain();
4233 }
4234 
appendToCurrentNodeAndPushElement(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes)4235 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElement(
4236     nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4237   nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4238   nsIContentHandle* elt =
4239       createElement(kNameSpaceID_XHTML, elementName->getName(), attributes,
4240                     currentNode, htmlCreator(elementName->getHtmlCreator()));
4241   appendElement(elt, currentNode);
4242   if (nsHtml5ElementName::ELT_TEMPLATE == elementName) {
4243     elt = getDocumentFragmentForTemplate(elt);
4244   }
4245   nsHtml5StackNode* node = createStackNode(elementName, elt);
4246   push(node);
4247 }
4248 
appendToCurrentNodeAndPushElementMayFoster(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes)4249 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(
4250     nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4251   nsAtom* popName = elementName->getName();
4252   nsIContentHandle* elt;
4253   nsHtml5StackNode* current = stack[currentPtr];
4254   if (current->isFosterParenting()) {
4255     elt = createAndInsertFosterParentedElement(
4256         kNameSpaceID_XHTML, popName, attributes,
4257         htmlCreator(elementName->getHtmlCreator()));
4258   } else {
4259     nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4260     elt = createElement(kNameSpaceID_XHTML, popName, attributes, currentNode,
4261                         htmlCreator(elementName->getHtmlCreator()));
4262     appendElement(elt, currentNode);
4263   }
4264   nsHtml5StackNode* node = createStackNode(elementName, elt, popName);
4265   push(node);
4266 }
4267 
appendToCurrentNodeAndPushElementMayFosterMathML(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes)4268 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterMathML(
4269     nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4270   nsAtom* popName = elementName->getName();
4271   bool markAsHtmlIntegrationPoint = false;
4272   if (nsHtml5ElementName::ELT_ANNOTATION_XML == elementName &&
4273       annotationXmlEncodingPermitsHtml(attributes)) {
4274     markAsHtmlIntegrationPoint = true;
4275   }
4276   nsIContentHandle* elt;
4277   nsHtml5StackNode* current = stack[currentPtr];
4278   if (current->isFosterParenting()) {
4279     elt = createAndInsertFosterParentedElement(
4280         kNameSpaceID_MathML, popName, attributes, htmlCreator(nullptr));
4281   } else {
4282     nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4283     elt = createElement(kNameSpaceID_MathML, popName, attributes, currentNode,
4284                         htmlCreator(nullptr));
4285     appendElement(elt, currentNode);
4286   }
4287   nsHtml5StackNode* node =
4288       createStackNode(elementName, elt, popName, markAsHtmlIntegrationPoint);
4289   push(node);
4290 }
4291 
annotationXmlEncodingPermitsHtml(nsHtml5HtmlAttributes * attributes)4292 bool nsHtml5TreeBuilder::annotationXmlEncodingPermitsHtml(
4293     nsHtml5HtmlAttributes* attributes) {
4294   nsHtml5String encoding =
4295       attributes->getValue(nsHtml5AttributeName::ATTR_ENCODING);
4296   if (!encoding) {
4297     return false;
4298   }
4299   return nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
4300              "application/xhtml+xml", encoding) ||
4301          nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
4302              "text/html", encoding);
4303 }
4304 
appendToCurrentNodeAndPushElementMayFosterSVG(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes)4305 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterSVG(
4306     nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4307   nsAtom* popName = elementName->getCamelCaseName();
4308   nsIContentHandle* elt;
4309   nsHtml5StackNode* current = stack[currentPtr];
4310   if (current->isFosterParenting()) {
4311     elt = createAndInsertFosterParentedElement(
4312         kNameSpaceID_SVG, popName, attributes,
4313         svgCreator(elementName->getSvgCreator()));
4314   } else {
4315     nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4316     elt = createElement(kNameSpaceID_SVG, popName, attributes, currentNode,
4317                         svgCreator(elementName->getSvgCreator()));
4318     appendElement(elt, currentNode);
4319   }
4320   nsHtml5StackNode* node = createStackNode(elementName, popName, elt);
4321   push(node);
4322 }
4323 
appendToCurrentNodeAndPushElementMayFoster(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes,nsIContentHandle * form)4324 void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(
4325     nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes,
4326     nsIContentHandle* form) {
4327   nsIContentHandle* elt;
4328   nsIContentHandle* formOwner =
4329       !form || fragment || isTemplateContents() ? nullptr : form;
4330   nsHtml5StackNode* current = stack[currentPtr];
4331   if (current->isFosterParenting()) {
4332     elt = createAndInsertFosterParentedElement(
4333         kNameSpaceID_XHTML, elementName->getName(), attributes, formOwner,
4334         htmlCreator(elementName->getHtmlCreator()));
4335   } else {
4336     nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4337     elt = createElement(kNameSpaceID_XHTML, elementName->getName(), attributes,
4338                         formOwner, currentNode,
4339                         htmlCreator(elementName->getHtmlCreator()));
4340     appendElement(elt, currentNode);
4341   }
4342   nsHtml5StackNode* node = createStackNode(elementName, elt);
4343   push(node);
4344 }
4345 
appendVoidElementToCurrentMayFoster(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes,nsIContentHandle * form)4346 void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFoster(
4347     nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes,
4348     nsIContentHandle* form) {
4349   nsAtom* name = elementName->getName();
4350   nsIContentHandle* elt;
4351   nsIContentHandle* formOwner =
4352       !form || fragment || isTemplateContents() ? nullptr : form;
4353   nsHtml5StackNode* current = stack[currentPtr];
4354   if (current->isFosterParenting()) {
4355     elt = createAndInsertFosterParentedElement(
4356         kNameSpaceID_XHTML, name, attributes, formOwner,
4357         htmlCreator(elementName->getHtmlCreator()));
4358   } else {
4359     nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4360     elt =
4361         createElement(kNameSpaceID_XHTML, name, attributes, formOwner,
4362                       currentNode, htmlCreator(elementName->getHtmlCreator()));
4363     appendElement(elt, currentNode);
4364   }
4365   elementPushed(kNameSpaceID_XHTML, name, elt);
4366   elementPopped(kNameSpaceID_XHTML, name, elt);
4367 }
4368 
appendVoidElementToCurrentMayFoster(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes)4369 void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFoster(
4370     nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4371   nsAtom* popName = elementName->getName();
4372   nsIContentHandle* elt;
4373   nsHtml5StackNode* current = stack[currentPtr];
4374   if (current->isFosterParenting()) {
4375     elt = createAndInsertFosterParentedElement(
4376         kNameSpaceID_XHTML, popName, attributes,
4377         htmlCreator(elementName->getHtmlCreator()));
4378   } else {
4379     nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4380     elt = createElement(kNameSpaceID_XHTML, popName, attributes, currentNode,
4381                         htmlCreator(elementName->getHtmlCreator()));
4382     appendElement(elt, currentNode);
4383   }
4384   elementPushed(kNameSpaceID_XHTML, popName, elt);
4385   elementPopped(kNameSpaceID_XHTML, popName, elt);
4386 }
4387 
appendVoidElementToCurrentMayFosterSVG(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes)4388 void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFosterSVG(
4389     nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4390   nsAtom* popName = elementName->getCamelCaseName();
4391   nsIContentHandle* elt;
4392   nsHtml5StackNode* current = stack[currentPtr];
4393   if (current->isFosterParenting()) {
4394     elt = createAndInsertFosterParentedElement(
4395         kNameSpaceID_SVG, popName, attributes,
4396         svgCreator(elementName->getSvgCreator()));
4397   } else {
4398     nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4399     elt = createElement(kNameSpaceID_SVG, popName, attributes, currentNode,
4400                         svgCreator(elementName->getSvgCreator()));
4401     appendElement(elt, currentNode);
4402   }
4403   elementPushed(kNameSpaceID_SVG, popName, elt);
4404   elementPopped(kNameSpaceID_SVG, popName, elt);
4405 }
4406 
appendVoidElementToCurrentMayFosterMathML(nsHtml5ElementName * elementName,nsHtml5HtmlAttributes * attributes)4407 void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFosterMathML(
4408     nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
4409   nsAtom* popName = elementName->getName();
4410   nsIContentHandle* elt;
4411   nsHtml5StackNode* current = stack[currentPtr];
4412   if (current->isFosterParenting()) {
4413     elt = createAndInsertFosterParentedElement(
4414         kNameSpaceID_MathML, popName, attributes, htmlCreator(nullptr));
4415   } else {
4416     nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4417     elt = createElement(kNameSpaceID_MathML, popName, attributes, currentNode,
4418                         htmlCreator(nullptr));
4419     appendElement(elt, currentNode);
4420   }
4421   elementPushed(kNameSpaceID_MathML, popName, elt);
4422   elementPopped(kNameSpaceID_MathML, popName, elt);
4423 }
4424 
appendVoidInputToCurrent(nsHtml5HtmlAttributes * attributes,nsIContentHandle * form)4425 void nsHtml5TreeBuilder::appendVoidInputToCurrent(
4426     nsHtml5HtmlAttributes* attributes, nsIContentHandle* form) {
4427   nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4428   nsIContentHandle* elt =
4429       createElement(kNameSpaceID_XHTML, nsGkAtoms::input, attributes,
4430                     !form || fragment || isTemplateContents() ? nullptr : form,
4431                     currentNode, htmlCreator(NS_NewHTMLInputElement));
4432   appendElement(elt, currentNode);
4433   elementPushed(kNameSpaceID_XHTML, nsGkAtoms::input, elt);
4434   elementPopped(kNameSpaceID_XHTML, nsGkAtoms::input, elt);
4435 }
4436 
appendVoidFormToCurrent(nsHtml5HtmlAttributes * attributes)4437 void nsHtml5TreeBuilder::appendVoidFormToCurrent(
4438     nsHtml5HtmlAttributes* attributes) {
4439   nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
4440   nsIContentHandle* elt =
4441       createElement(kNameSpaceID_XHTML, nsGkAtoms::form, attributes,
4442                     currentNode, htmlCreator(NS_NewHTMLFormElement));
4443   formPointer = elt;
4444   appendElement(elt, currentNode);
4445   elementPushed(kNameSpaceID_XHTML, nsGkAtoms::form, elt);
4446   elementPopped(kNameSpaceID_XHTML, nsGkAtoms::form, elt);
4447 }
4448 
requestSuspension()4449 void nsHtml5TreeBuilder::requestSuspension() {
4450   tokenizer->requestSuspension();
4451 }
4452 
4453 ;
isInForeign()4454 bool nsHtml5TreeBuilder::isInForeign() {
4455   return currentPtr >= 0 && stack[currentPtr]->ns != kNameSpaceID_XHTML;
4456 }
4457 
isInForeignButNotHtmlOrMathTextIntegrationPoint()4458 bool nsHtml5TreeBuilder::isInForeignButNotHtmlOrMathTextIntegrationPoint() {
4459   if (currentPtr < 0) {
4460     return false;
4461   }
4462   return !isSpecialParentInForeign(stack[currentPtr]);
4463 }
4464 
setFragmentContext(nsAtom * context,int32_t ns,nsIContentHandle * node,bool quirks)4465 void nsHtml5TreeBuilder::setFragmentContext(nsAtom* context, int32_t ns,
4466                                             nsIContentHandle* node,
4467                                             bool quirks) {
4468   this->contextName = context;
4469   this->contextNamespace = ns;
4470   this->contextNode = node;
4471   this->fragment = (!!contextName);
4472   this->quirks = quirks;
4473 }
4474 
currentNode()4475 nsIContentHandle* nsHtml5TreeBuilder::currentNode() {
4476   return stack[currentPtr]->node;
4477 }
4478 
isScriptingEnabled()4479 bool nsHtml5TreeBuilder::isScriptingEnabled() { return scriptingEnabled; }
4480 
setScriptingEnabled(bool scriptingEnabled)4481 void nsHtml5TreeBuilder::setScriptingEnabled(bool scriptingEnabled) {
4482   this->scriptingEnabled = scriptingEnabled;
4483 }
4484 
setForceNoQuirks(bool forceNoQuirks)4485 void nsHtml5TreeBuilder::setForceNoQuirks(bool forceNoQuirks) {
4486   this->forceNoQuirks = forceNoQuirks;
4487 }
4488 
setIsSrcdocDocument(bool isSrcdocDocument)4489 void nsHtml5TreeBuilder::setIsSrcdocDocument(bool isSrcdocDocument) {
4490   this->setForceNoQuirks(isSrcdocDocument);
4491 }
4492 
flushCharacters()4493 void nsHtml5TreeBuilder::flushCharacters() {
4494   if (charBufferLen > 0) {
4495     if ((mode == IN_TABLE || mode == IN_TABLE_BODY || mode == IN_ROW) &&
4496         charBufferContainsNonWhitespace()) {
4497       errNonSpaceInTable();
4498       reconstructTheActiveFormattingElements();
4499       if (!stack[currentPtr]->isFosterParenting()) {
4500         appendCharacters(currentNode(), charBuffer, 0, charBufferLen);
4501         charBufferLen = 0;
4502         return;
4503       }
4504       int32_t tablePos = findLastOrRoot(nsHtml5TreeBuilder::TABLE);
4505       int32_t templatePos = findLastOrRoot(nsHtml5TreeBuilder::TEMPLATE);
4506       if (templatePos >= tablePos) {
4507         appendCharacters(stack[templatePos]->node, charBuffer, 0,
4508                          charBufferLen);
4509         charBufferLen = 0;
4510         return;
4511       }
4512       nsHtml5StackNode* tableElt = stack[tablePos];
4513       insertFosterParentedCharacters(charBuffer, 0, charBufferLen,
4514                                      tableElt->node, stack[tablePos - 1]->node);
4515       charBufferLen = 0;
4516       return;
4517     }
4518     appendCharacters(currentNode(), charBuffer, 0, charBufferLen);
4519     charBufferLen = 0;
4520   }
4521 }
4522 
charBufferContainsNonWhitespace()4523 bool nsHtml5TreeBuilder::charBufferContainsNonWhitespace() {
4524   for (int32_t i = 0; i < charBufferLen; i++) {
4525     switch (charBuffer[i]) {
4526       case ' ':
4527       case '\t':
4528       case '\n':
4529       case '\r':
4530       case '\f': {
4531         continue;
4532       }
4533       default: {
4534         return true;
4535       }
4536     }
4537   }
4538   return false;
4539 }
4540 
newSnapshot()4541 nsAHtml5TreeBuilderState* nsHtml5TreeBuilder::newSnapshot() {
4542   jArray<nsHtml5StackNode*, int32_t> listCopy =
4543       jArray<nsHtml5StackNode*, int32_t>::newJArray(listPtr + 1);
4544   for (int32_t i = 0; i < listCopy.length; i++) {
4545     nsHtml5StackNode* node = listOfActiveFormattingElements[i];
4546     if (node) {
4547       nsHtml5StackNode* newNode = new nsHtml5StackNode(-1);
4548       newNode->setValues(node->getFlags(), node->ns, node->name, node->node,
4549                          node->popName, node->attributes->cloneAttributes(),
4550                          node->getHtmlCreator());
4551       listCopy[i] = newNode;
4552     } else {
4553       listCopy[i] = nullptr;
4554     }
4555   }
4556   jArray<nsHtml5StackNode*, int32_t> stackCopy =
4557       jArray<nsHtml5StackNode*, int32_t>::newJArray(currentPtr + 1);
4558   for (int32_t i = 0; i < stackCopy.length; i++) {
4559     nsHtml5StackNode* node = stack[i];
4560     int32_t listIndex = findInListOfActiveFormattingElements(node);
4561     if (listIndex == -1) {
4562       nsHtml5StackNode* newNode = new nsHtml5StackNode(-1);
4563       newNode->setValues(node->getFlags(), node->ns, node->name, node->node,
4564                          node->popName, nullptr, node->getHtmlCreator());
4565       stackCopy[i] = newNode;
4566     } else {
4567       stackCopy[i] = listCopy[listIndex];
4568       stackCopy[i]->retain();
4569     }
4570   }
4571   jArray<int32_t, int32_t> templateModeStackCopy =
4572       jArray<int32_t, int32_t>::newJArray(templateModePtr + 1);
4573   nsHtml5ArrayCopy::arraycopy(templateModeStack, templateModeStackCopy,
4574                               templateModeStackCopy.length);
4575   return new nsHtml5StateSnapshot(stackCopy, listCopy, templateModeStackCopy,
4576                                   formPointer, headPointer, mode, originalMode,
4577                                   framesetOk, needToDropLF, quirks);
4578 }
4579 
snapshotMatches(nsAHtml5TreeBuilderState * snapshot)4580 bool nsHtml5TreeBuilder::snapshotMatches(nsAHtml5TreeBuilderState* snapshot) {
4581   jArray<nsHtml5StackNode*, int32_t> stackCopy = snapshot->getStack();
4582   int32_t stackLen = snapshot->getStackLength();
4583   jArray<nsHtml5StackNode*, int32_t> listCopy =
4584       snapshot->getListOfActiveFormattingElements();
4585   int32_t listLen = snapshot->getListOfActiveFormattingElementsLength();
4586   jArray<int32_t, int32_t> templateModeStackCopy =
4587       snapshot->getTemplateModeStack();
4588   int32_t templateModeStackLen = snapshot->getTemplateModeStackLength();
4589   if (stackLen != currentPtr + 1 || listLen != listPtr + 1 ||
4590       templateModeStackLen != templateModePtr + 1 ||
4591       formPointer != snapshot->getFormPointer() ||
4592       headPointer != snapshot->getHeadPointer() ||
4593       mode != snapshot->getMode() ||
4594       originalMode != snapshot->getOriginalMode() ||
4595       framesetOk != snapshot->isFramesetOk() ||
4596       needToDropLF != snapshot->isNeedToDropLF() ||
4597       quirks != snapshot->isQuirks()) {
4598     return false;
4599   }
4600   for (int32_t i = listLen - 1; i >= 0; i--) {
4601     if (!listCopy[i] && !listOfActiveFormattingElements[i]) {
4602       continue;
4603     } else if (!listCopy[i] || !listOfActiveFormattingElements[i]) {
4604       return false;
4605     }
4606     if (listCopy[i]->node != listOfActiveFormattingElements[i]->node) {
4607       return false;
4608     }
4609   }
4610   for (int32_t i = stackLen - 1; i >= 0; i--) {
4611     if (stackCopy[i]->node != stack[i]->node) {
4612       return false;
4613     }
4614   }
4615   for (int32_t i = templateModeStackLen - 1; i >= 0; i--) {
4616     if (templateModeStackCopy[i] != templateModeStack[i]) {
4617       return false;
4618     }
4619   }
4620   return true;
4621 }
4622 
loadState(nsAHtml5TreeBuilderState * snapshot)4623 void nsHtml5TreeBuilder::loadState(nsAHtml5TreeBuilderState* snapshot) {
4624   mCurrentHtmlScriptIsAsyncOrDefer = false;
4625   jArray<nsHtml5StackNode*, int32_t> stackCopy = snapshot->getStack();
4626   int32_t stackLen = snapshot->getStackLength();
4627   jArray<nsHtml5StackNode*, int32_t> listCopy =
4628       snapshot->getListOfActiveFormattingElements();
4629   int32_t listLen = snapshot->getListOfActiveFormattingElementsLength();
4630   jArray<int32_t, int32_t> templateModeStackCopy =
4631       snapshot->getTemplateModeStack();
4632   int32_t templateModeStackLen = snapshot->getTemplateModeStackLength();
4633   for (int32_t i = 0; i <= listPtr; i++) {
4634     if (listOfActiveFormattingElements[i]) {
4635       listOfActiveFormattingElements[i]->release(this);
4636     }
4637   }
4638   if (listOfActiveFormattingElements.length < listLen) {
4639     listOfActiveFormattingElements =
4640         jArray<nsHtml5StackNode*, int32_t>::newJArray(listLen);
4641   }
4642   listPtr = listLen - 1;
4643   for (int32_t i = 0; i <= currentPtr; i++) {
4644     stack[i]->release(this);
4645   }
4646   if (stack.length < stackLen) {
4647     stack = jArray<nsHtml5StackNode*, int32_t>::newJArray(stackLen);
4648   }
4649   currentPtr = stackLen - 1;
4650   if (templateModeStack.length < templateModeStackLen) {
4651     templateModeStack =
4652         jArray<int32_t, int32_t>::newJArray(templateModeStackLen);
4653   }
4654   templateModePtr = templateModeStackLen - 1;
4655   for (int32_t i = 0; i < listLen; i++) {
4656     nsHtml5StackNode* node = listCopy[i];
4657     if (node) {
4658       nsHtml5StackNode* newNode = createStackNode(
4659           node->getFlags(), node->ns, node->name, node->node, node->popName,
4660           node->attributes->cloneAttributes(), node->getHtmlCreator());
4661       listOfActiveFormattingElements[i] = newNode;
4662     } else {
4663       listOfActiveFormattingElements[i] = nullptr;
4664     }
4665   }
4666   for (int32_t i = 0; i < stackLen; i++) {
4667     nsHtml5StackNode* node = stackCopy[i];
4668     int32_t listIndex = findInArray(node, listCopy);
4669     if (listIndex == -1) {
4670       nsHtml5StackNode* newNode =
4671           createStackNode(node->getFlags(), node->ns, node->name, node->node,
4672                           node->popName, nullptr, node->getHtmlCreator());
4673       stack[i] = newNode;
4674     } else {
4675       stack[i] = listOfActiveFormattingElements[listIndex];
4676       stack[i]->retain();
4677     }
4678   }
4679   nsHtml5ArrayCopy::arraycopy(templateModeStackCopy, templateModeStack,
4680                               templateModeStackLen);
4681   formPointer = snapshot->getFormPointer();
4682   headPointer = snapshot->getHeadPointer();
4683   mode = snapshot->getMode();
4684   originalMode = snapshot->getOriginalMode();
4685   framesetOk = snapshot->isFramesetOk();
4686   needToDropLF = snapshot->isNeedToDropLF();
4687   quirks = snapshot->isQuirks();
4688 }
4689 
findInArray(nsHtml5StackNode * node,jArray<nsHtml5StackNode *,int32_t> arr)4690 int32_t nsHtml5TreeBuilder::findInArray(
4691     nsHtml5StackNode* node, jArray<nsHtml5StackNode*, int32_t> arr) {
4692   for (int32_t i = listPtr; i >= 0; i--) {
4693     if (node == arr[i]) {
4694       return i;
4695     }
4696   }
4697   return -1;
4698 }
4699 
nodeFromStackWithBlinkCompat(int32_t stackPos)4700 nsIContentHandle* nsHtml5TreeBuilder::nodeFromStackWithBlinkCompat(
4701     int32_t stackPos) {
4702   if (stackPos > 511) {
4703     errDeepTree();
4704     return stack[511]->node;
4705   }
4706   return stack[stackPos]->node;
4707 }
4708 
getFormPointer()4709 nsIContentHandle* nsHtml5TreeBuilder::getFormPointer() { return formPointer; }
4710 
getHeadPointer()4711 nsIContentHandle* nsHtml5TreeBuilder::getHeadPointer() { return headPointer; }
4712 
4713 jArray<nsHtml5StackNode*, int32_t>
getListOfActiveFormattingElements()4714 nsHtml5TreeBuilder::getListOfActiveFormattingElements() {
4715   return listOfActiveFormattingElements;
4716 }
4717 
getStack()4718 jArray<nsHtml5StackNode*, int32_t> nsHtml5TreeBuilder::getStack() {
4719   return stack;
4720 }
4721 
getTemplateModeStack()4722 jArray<int32_t, int32_t> nsHtml5TreeBuilder::getTemplateModeStack() {
4723   return templateModeStack;
4724 }
4725 
getMode()4726 int32_t nsHtml5TreeBuilder::getMode() { return mode; }
4727 
getOriginalMode()4728 int32_t nsHtml5TreeBuilder::getOriginalMode() { return originalMode; }
4729 
isFramesetOk()4730 bool nsHtml5TreeBuilder::isFramesetOk() { return framesetOk; }
4731 
isNeedToDropLF()4732 bool nsHtml5TreeBuilder::isNeedToDropLF() { return needToDropLF; }
4733 
isQuirks()4734 bool nsHtml5TreeBuilder::isQuirks() { return quirks; }
4735 
getListOfActiveFormattingElementsLength()4736 int32_t nsHtml5TreeBuilder::getListOfActiveFormattingElementsLength() {
4737   return listPtr + 1;
4738 }
4739 
getStackLength()4740 int32_t nsHtml5TreeBuilder::getStackLength() { return currentPtr + 1; }
4741 
getTemplateModeStackLength()4742 int32_t nsHtml5TreeBuilder::getTemplateModeStackLength() {
4743   return templateModePtr + 1;
4744 }
4745 
initializeStatics()4746 void nsHtml5TreeBuilder::initializeStatics() {}
4747 
releaseStatics()4748 void nsHtml5TreeBuilder::releaseStatics() {}
4749 
4750 #include "nsHtml5TreeBuilderCppSupplement.h"
4751